Pattern to use additional variables in do block?

I’m trying to write a small package to process files in an easy way. I often write very similar scripts that open files, read them record by record, process the record in some way (modify it or filter it out), close the files, etc… so I’d like to have a generic do-function to simplify that.

This is a minimal example, the real thing opens files and such, but that’s enough for my question :

process(f, collection) = f.(collection)

process(1:5) do record
    2*record
end

Now my issue is that I also often want to compute some overall statistics over records, but I’m not too sure how to deal with this gracefully, e.g. using globals isn’t so nice :

global total = 0
process(1:5) do record
    global total += record
    2*record
end

Is there a good way to do this ?

process(x) = 10x
process(f, collection) = f.(collection)

let total = 0
    results = process(1:5) do record
        total += record
        2*record
    end
    total, results
end
3 Likes

Note that global would only be needed if you are using that in global scope. A better idea is to wrap all into a function, and then the variables local to the scope of the function can be used inside the closure (that is what is going on in the example above with the let as well):


julia>  function f(v)
           s = 0
           idxs = findall(v) do x
             if x > 0
               s += x^2
               return true
             else
               return false
             end
           end
           return idxs, s
       end
f (generic function with 1 method)

julia> v = rand(-5:5,10);

julia> f(v)
([3, 4, 5, 6, 10], 71)

Meaning that if you are implementing functions like that, there should be no problem in principle to compute what you want.

1 Like