Closures and Let Blocks

Anyone have any basic examples of when to use/what the effects are of having a let block along with a closure?

I’ve been looking to learn more about functional programming in Julia and reading through the manual, but I don’t think I understand the uses of a let block from reading the docs.

Any help is appreciated, and any more resources in functional programming with Julia (or in general ) would be greatly appreciated!!

2 Likes

The classic case is when you want to create a new binding that will be captured in a closure. For example if you’re modifying a value in a while loop and capturing it, then that might not do what you want:

function fib_closures(n)
    fns = []
    a = b = 1
    while b <= n
        push!(fns, x -> x + b)
        a, b = b, a + b
    end
    return fns
end
julia> [f(0) for f in fib_closures(10)]
5-element Vector{Int64}:
 13
 13
 13
 13
 13

If you want each captured closure to get a private copy of b then you need to use let to create a fresh binding for each one (which can have the same name):

function fib_closures(n)
    fns = []
    a = b = 1
    while b <= n
        let b = b
            push!(fns, x -> x + b)
        end
        a, b = b, a + b
    end
    return fns
end
julia> [f(0) for f in fib_closures(10)]
5-element Vector{Int64}:
 1
 2
 3
 5
 8
13 Likes

Thank you, this helps a bunch!
I also understand there’s some well known type stability issues when referencing enclosed variables. I’ve heard that a let block can help with speed things up a bit, though I don’t quite understand why. Any insights on this?

See Performance of captured variable in the manual.

2 Likes

Thank you! Must’ve slipped through the cracks while going through the manual. Also, I’ve been using julia-repl in emacs quite a bit, so thanks for that!