How to convert a function to a string

444 views
Skip to first unread message

Adam Savitzky

unread,
Feb 21, 2013, 1:47:13 PM2/21/13
to julia...@googlegroups.com
I want to take a function and serialize it as a string and then deserialize it back into function form. How can I do this?

I've played around with serialize but I'm not sure if that's right. I've also tried the string constructor but that just gives me "# function"

Example:
(x) -> x^2 should be converted to "(x) -> x^2"

Kevin Squire

unread,
Feb 21, 2013, 2:52:12 PM2/21/13
to julia...@googlegroups.com
Do you have a particular application in mind that you can describe further?

Unless prevented by some means (such as quoting), a function is compiled immediately, and the original string representation is discarded.  

If you quote the function, that will give you an Expr object that you can manipulate and evaluate (i.e., compile), and if needed turn into a string that is equivalent to (but usually a bit different from) the original function string.

julia> a = quote (x) -> x^2 end
quote  
# line 1:
    x
->begin  # none, line 1:
           
^(x,2)
       
end
end

julia
> a = :((x) -> x^2)  # alternative quoting mechanism
:(x->begin  # none, line 1:
           
^(x,2)
       
end)

julia
> typeof(a)
Expr

julia
> a.head
:->

julia
> a.args

2-element Any Array:
 
:x                                  
 quote  
# none, line 1:
   
^(x,2)
end

julia
> string(a)
"quote  # line 1:\n    x->begin  # none, line 1:\n            ^(x,2)\n        end\nend"

julia
> sqr = eval(a)
# function

julia
> sqr(3)
9

Kevin

Patrick O'Leary

unread,
Feb 21, 2013, 2:57:49 PM2/21/13
to julia...@googlegroups.com
It's not necessarily a good idea, but you can actually get an AST out of a Function. I take advantage of this in QuickCheck. It's easier for anonymous functions:

# Conditional properties
function condproperty(f::Function, ntests, maxtests, argconds...)
    if !isa(f.code, LambdaStaticData)
        error("Property must be expressed as an anonymous function")
    end
    vars = f.code.ast.args[1]
    typs = [eval(var.args[2]) for var in vars]
    arggens = [size -> generator(typ, size) for typ in typs]
    check_property(f, arggens, argconds, ntests, maxtests)
end

A recent StackOverflow discussion showed how to extend this reflection capability to generic functions using methods(): http://stackoverflow.com/questions/14124456/access-the-ast-for-generic-functions-in-julia/14883257#14883257

Adam Savitzky

unread,
Feb 21, 2013, 3:16:59 PM2/21/13
to julia...@googlegroups.com
So this ought to do it, then:

to_string(f::Function) = string([ref(method, 3) for method in methods(f, (Any, Any))])

It doesn't work for standard library functions, but it should take any user defined functions and serialize all of their methods.

Does anyone notice any red flags?

Patrick O'Leary

unread,
Feb 21, 2013, 3:22:53 PM2/21/13
to julia...@googlegroups.com
Well, we're back to Kevin's question of what you're trying to accomplish in the first place.

Also, you're only going to get AST objects for f(::Any, ::Any). Also, that might be a compressed AST. Also, I don't think methods() will work for an anonymous function (might be wrong on that one).

Adam Savitzky

unread,
Feb 21, 2013, 3:24:01 PM2/21/13
to julia...@googlegroups.com
On second thought that doesn't work at all.

Adam Savitzky

unread,
Feb 21, 2013, 3:39:50 PM2/21/13
to julia...@googlegroups.com
Well I can think of numerous reasons why you would want a string representation of a function.

My specific use case is for sharing code between machines via a web service. The client needs to be able to serialize code and send it to the web service.

I've also used this in other languages to do things like build dependency trees between functions. For example:

function a()
   return b() + c()
end

function b()
   return 2
end

function c()
    return d() * d()
end

function d()
    return 4
end

I might have a function:

solve_system(a, b, c, d)

If I can serialize the body of those functions then I can construct the tree using regex or a similar strategy:
a - b
|
c - d

I then know that b and d need to be evaluated first, then c, then a, in order to solve the system.

Patrick O'Leary

unread,
Feb 21, 2013, 3:49:57 PM2/21/13
to julia...@googlegroups.com
I'm pretty sure you want to stick with serialize/deserialize for the web service. This is how Julia's standard remote call mechanism works. Take a look at https://github.com/JuliaLang/julia/blob/master/base/multi.jl for some examples.

The dependency graphing is much more interesting, though I'd want to work with the AST form in that case. I am interested in the idea of having a reliable AST reflection available as a part of Base.Meta, but it won't be a one-liner for the reason of the special cases. However, that still doesn't give you the type information you need to resolve the dependencies without access to the type inference machinery, which we can't currently get at. Neat idea, though.

Adam Savitzky

unread,
Feb 21, 2013, 5:38:22 PM2/21/13
to julia...@googlegroups.com
Ok, I'll try playing with the machinery inside multi.jl
Reply all
Reply to author
Forward
0 new messages