Saving the values of all variabled declared in a block Often when running exprimental code to empirically investigate an algorithm, you tweak a parameter, then rerun the code, and generate a bunch of saved models for various parameters.

To make sure I don't loose what the parameters were set to I defined a macro that saves there values.

module Util
using JLD

export @param_save #...

function names_candidates(blk::Expr)
    names_in_block = Vector{Symbol}()
    for a in blk.args
        typeof(a) &lt;: Expr || continue
        if a.head == :(=)
            push!(names_in_block, a.args[1])
        else #Recurse, so we captured things in blocks or behind `const`
            append!(names_in_block, names_candidates(a))
        end
    end
    names_in_block
end

macro param_save(filename, blk::Expr)
    names_in_block =  names_candidates(blk)
    quote
        $(esc(blk))
        names_defined = Set($(names_in_block)) ∩ Set(names(current_module()))
        names_and_vals =[(string(name), eval(name)) for name in names_defined]
        println("Paramaters -- saving to $($filename)")
        println("----------")
        println(join(("$n = $v" for (n,v) in names_and_vals),"\n"))
        JLD.save($filename, Base.flatten(names_and_vals)...)
        println("----------")
    end
end
#...
end #module


Usage:

using Util

base_name = "paper_v1"
param_save_fn =  "../models/adagram/$(base_name).params.jld"
output_fn = "../models/adagram/$(base_name).adagram_model"#"file to save the model (in Julia format)"
@assert !isfile(output_fn)
@param_save param_save_fn begin
        nprocessors = nprocs()
        train_fn  =  "../data/corpora/WikiCorp/tokenised_lowercase_WestburyLab.wikicorp.201004.txt" #"training text data"
        output_fn = output_fn #file to save the model (in Julia format)"
        dict_fn = "../data/corpora/WikiCorp/tokenised_lowercase_WestburyLab.wikicorp.201004.1gram" #"dictionary file with word frequencies"

        window = 10 #"(max) window size" C in the paper
        min_freq  = 20 #"min. frequency of the word"
        remove_top_k = 0 #"remove top K most frequent words"
        dim  = 300 #"dimensionality of representations"
        prototypes = 5 #"number of word prototypes" T in the paper
        alpha = 0.15 #"prior probability of allocating a new prototype"
        d  = 0.0 #"parameter of Pitman-Yor process" D in paper
        subsample = 1e-5 #"subsampling treshold. useful value is 1e-5"
        context_cut  = true #"randomly reduce size of the context"
        epochs = 1 #"number of epochs to train"
        initcount = 1. #"initial weight (count) on first sense for each word"
        stopwords = Set{AbstractString}() #"list of stop words"
        sense_treshold = 1e-10 #"minimal probability of a meaning to contribute into gradients"
        save_treshold = 0.0 #"minimal probability of a meaning to save after training"
end


Output:

Paramaters -- saving to ../models/adagram/paper_v1btempexample.params.jld
----------
train_fn = ../data/corpora/WikiCorp/tokenised_lowercase_WestburyLab.wikicorp.201004.txt
alpha = 0.15
subsample = 1.0e-5
sense_treshold = 1.0e-10
initcount = 1.0
nprocessors = 1
epochs = 1
window = 10
output_fn = ../models/adagram/paper_v1btempexample.adagram_model
min_freq = 20
prototypes = 5
context_cut = true
stopwords = Set{AbstractString}()
remove_top_k = 0
save_treshold = 0.0
dict_fn = ../data/corpora/WikiCorp/tokenised_lowercase_WestburyLab.wikicorp.201004.1gram
dim = 300
d = 0.0
----------


Writing code with macros is hard.
It took me a few shots to get the escaping all right.

Is this reasonable code?
AFAICT julia doesn't have a method like pythons locals() that lists all variables in a given scope. 
So I have to work around that by finding possible variables in the AST then cross referencing that against all variables in the module.
Since this will be used at toplevel anyway, I would just wrap all the parameters in a module.

macro param_save(file, blk)
    modname = gensym()
    Expr(:toplevel,
        Expr(:using, :JLD),
        Expr(:module, false, modname, esc(blk)),
        quote
            JLD.save($file, Dict(
                string(n) =&gt; eval($modname, n)
                for n in names($modname, true)
                if n ≠ $(Meta.quot(modname))))
        end)
end