Macros to create anonymous function

Is there a way to use a macro like

default_v = 1
af = @anonymous_func begin 
   @show v
end v=default_v

to get transformed into

(;v=1) -> @show v

I am wondering whether this is possible as the macro is created before default_v is known, right?

As a step into the right direction though I would be happy to transform

af = @anonymous_func begin 
   @show v
end v=1

into the anonymous function shown above. I am having difficulties parsing the expr... as something using as the keyword arguments like:

macro anonymous_func(body::Expr, expr...)
    expr = quote
        (;$expr) -> begin eval($body) end
  end
   esc(expr)

doesn’t work.

It’s not very elegant, but you can mess around with the Expr objects directly:

julia> :((;a=1) -> a) |> dump
Expr
  head: Symbol ->
  args: Array{Any}((2,))
    1: Expr
      head: Symbol tuple
      args: Array{Any}((1,))
        1: Expr
          head: Symbol parameters
          args: Array{Any}((1,))
            1: Expr
              head: Symbol kw
              args: Array{Any}((2,))
                1: Symbol a
                2: Int64 1
    2: Expr
      head: Symbol block
      args: Array{Any}((2,))
        1: LineNumberNode
          line: Int64 1
          file: Symbol REPL[338]
        2: Symbol a

So something like this:

macro anonymous_func(body::Expr, expr...)
           leftside =  Expr(:tuple, Expr(:parameters, [Expr(:kw, e.args[1], e.args[2]) for e in expr]...)) 
           out = Expr(:(->), leftside, body)
           esc(out)
       end
julia> foo = @anonymous_func begin
           v + w
       end v = 10 w = 1
#427 (generic function with 1 method)

julia> foo()
11

julia> foo(v = 2, w = 3)
5

Obviously that macro needs a lot more safety checking and attention overall… but it can get the job done.

3 Likes

Thanks a lot always learning new stuff here :slight_smile: