Is there any way to run name resolution on an arbitrary expression without running it? e.g. I would like to take an expression such as
quote
x = 1
y = 2*x + 1
z = x^2 - 1
f(x) = 2*x + 1
end
and be told that the names defined in the scope of this block are x, y, z, f and the names *, +, ^, - are pulled in from outside the scope of this block. Bonus points if it can tell me that there's a sub-scope defined in the body of f which creates it's own name x and pulls in + from an enclosing scope.
This question appeared in the Julia Zulip community
Thanks to Takafumi for showing me how to solve this on Zulip
We can get a list of locally defined names in the outermost scope of a julia expression like so:
ex = quote
x = 1
y = 2*x + 1
z = x^2 - 1
f(x) = 2*x + 1
end
using JuliaVariables, MLStyle
function get_locals(ex::Expr)
vars = (solve_from_local ∘ simplify_ex)(ex).args[1].bounds
map(x -> x.name, vars)
end
julia> get_locals(ex)
4-element Array{Symbol,1}:
:f
:y
:z
:x
and we can get the symbols pulled in from outside the scope like this:
_get_outers(_) = Symbol[]
_get_outers(x::Var) = x.is_global ? [x.name] : Symbol[]
function _get_outers(ex::Expr)
#match ex begin
Expr(:(=), _, rhs) => _get_outers(rhs)
Expr(:tuple, _..., Expr(:(=), _, rhs)) => _get_outers(rhs)
Expr(_, args...) => mapreduce(_get_outers, vcat, args)
end
end
get_outers(ex) = (unique! ∘ _get_outers ∘ solve_from_local ∘ simplify_ex)(ex)
julia> get_outers(ex)
6-element Array{Symbol,1}:
:+
:*
:-
:^
Related
I want to loop over a list of variables nad output the variable name and value. E.g., say I have x=1 and y=2, then I want an output
x is 1
y is 2
I suspect I need to use Symbols for this. Here is my approach, but it isn't working:
function t(x,y)
for i in [x,y]
println("$(Symbol(i)) is $(eval(i))") # outputs "1 is 1" and "2 is 2"
end
end
t(1, 2)
Is there a way to achieve this? I guess a Dictionary would work, but would be interested to see if Symbols can also be used here.
One option is to use a NamedTuple:
julia> x = 1; y = 2
2
julia> vals = (; x, y)
(x = 1, y = 2)
julia> for (n, v) ∈ pairs(vals)
println("$n is $v")
end
x is 1
y is 2
Note the semicolon in (; x, y), which turns the x and y into kwargs so that the whole expression becomes shorthand for (x = x, y = y).
I will also add that your question looks like like you are trying to dynamically work with variable names in global scope, which is generally discouraged and an indication that you probably should be considering a datastructure that holds values alongside labels, such as the dictionary proposed in the other answer or a NamedTuple. You can google around if you want to read more on this, here's a related SO question:
Is it a good idea to dynamically create variables?
You can do this by passing the variable names:
x = 1
y = 2
function t(a, b)
for i in [a, b]
println("$(i) is $(eval(i))")
end
end
t(:x, :y)
x is 1
y is 2
At the start of the function, there's no record of the "x"-ness of x, or the "y"-ness of y. The function only sees 1 and 2. It's a bit confusing that you also called your two local variables x and y, I renamed them to show what's happening more clearly.
A solution with dictionaries would be nicer:
dict = Dict()
dict[:x] = 1
dict[:y] = 2
function t(d)
for k in keys(d)
println("$(k) is $(d[k])")
end
end
t(dict)
y is 2
x is 1
If you rather want to see programmatically what variables are present you could use varinfo or names:
julia> x=5; y=7;
julia> varinfo()
name size summary
–––––––––––––––– ––––––––––– –––––––
Base Module
Core Module
InteractiveUtils 316.128 KiB Module
Main Module
ans 8 bytes Int64
x 8 bytes Int64
y 8 bytes Int64
julia> names(Main)
7-element Vector{Symbol}:
:Base
:Core
:InteractiveUtils
:Main
:ans
:x
With any given name it's value can be obtained via getfield:
julia> getfield(Main, :x)
5
If you are rather inside a function than use #locals macro:
julia> function f(a)
b=5
c=8
#show Base.#locals
end;
julia> f(1)
#= REPL[13]:4 =# Base.#locals() = Dict{Symbol, Any}(:a => 1, :b => 5, :c => 8)
Dict{Symbol, Any} with 3 entries:
:a => 1
:b => 5
:c => 8
I came across Julia in some graduate research and have done a few projects already in C++. I'm trying to "translate" some of my C++ work into Julia to compare performance, among other things.
Basically what I'm trying to do is implement something like the functional library from C++ such that I can do something like
g(x, b) = x*b # Modifier function
A = [1,2,...] # Some array of values
f(x) = 1 # Initialize the function
### This is the part that I am seeking
for i = 1:length(A)
f(x) = f(x)*g(x, A[i]) # This thing right here
end
###
and then be able to call f(x) and get the value of all the g(x, _) terms included (similar to using bind in C++)
I'm not sure if there is native syntax to support this, or if I'll need to look into some symbolic representation stuff. Any help is appreciated!
You are probably looking for this:
julia> g(x, b) = x * b
g (generic function with 1 method)
julia> bind(g, b) = x -> g(x, b) # a general way to bind the second argument in a two argument function
bind (generic function with 1 method)
julia> A = [1, 2, 3]
3-element Vector{Int64}:
1
2
3
julia> const f = bind(g, 10) # bind a second argument of our specific function g to 10; I use use const for performance reasons only
#1 (generic function with 1 method)
julia> f.(A) # broadcasting f, as you want to apply it to a collection of arguments
3-element Vector{Int64}:
10
20
30
julia> f(A) # in this particular case this also works as A*10 is a valid operation, but in general broadcasting would be required
3-element Vector{Int64}:
10
20
30
In particular for fixing the first and the second argument of the two argument function there are standard functions in Julia Base that are called Base.Fix1 and Base.Fix2 respectively.
You may be looking for the function composition operator ∘
help?> ∘
"∘" can be typed by \circ<tab>
search: ∘
f ∘ g
Compose functions: i.e. (f ∘ g)(args...) means f(g(args...)). The ∘ symbol can be
entered in the Julia REPL (and most editors, appropriately configured) by typing
\circ<tab>.
Function composition also works in prefix form: ∘(f, g) is the same as f ∘ g. The
prefix form supports composition of multiple functions: ∘(f, g, h) = f ∘ g ∘ h and
splatting ∘(fs...) for composing an iterable collection of functions.
Examples
≡≡≡≡≡≡≡≡≡≡
julia> map(uppercase∘first, ["apple", "banana", "carrot"])
3-element Vector{Char}:
'A': ASCII/Unicode U+0041 (category Lu: Letter, uppercase)
'B': ASCII/Unicode U+0042 (category Lu: Letter, uppercase)
'C': ASCII/Unicode U+0043 (category Lu: Letter, uppercase)
julia> fs = [
x -> 2x
x -> x/2
x -> x-1
x -> x+1
];
julia> ∘(fs...)(3)
3.0
so, for example
julia> g(b) = function(x); x*b; end # modifier function
g (generic function with 1 method)
julia> g(3)(2)
6
julia> f() = 3.14
f (generic function with 1 method)
julia> h = g(2) ∘ f
var"#1#2"{Int64}(2) ∘ f
julia> h()
6.28
When f(x-1) is called, is it calling f(x) = x+10 or f(x) = if ...
Is this a tail recursion?
How should I rewrite it using static / dynamic allocation?
let fun f(x) = x + 10
in
let fun f(x) = if x < 1 then 0 else f(x-1)
in f(3)
end
end
Before addressing your questions, here are some observations about your code:
There are two functions f, one inside the other. They're different from one another.
To lessen this confusion you can rename the inner function to g:
let fun f(x) = x + 10
in
let fun g(x) = if x < 1 then 0 else g(x-1)
in g(3)
end
end
This clears up which function calls which by the following rules: The outer f is defined inside the outer in-end, but is immediately shadowed by the inner f. So any reference to f on the right-hand side of the inner fun f(x) = if ... is shadowed because fun enables self-recursion. And any reference to f within the inner in-end is shadowed
In the following tangential example the right-hand side of an inner declaration f does not shadow the outer f if we were using val rather than fun:
let fun f(x) = if (x mod 2 = 0) then x - 10 else x + 10
in
let val f = fn x => f(x + 2) * 2
in f(3)
end
end
If the inner f is renamed to g in this second piece of code, it'd look like:
let fun f(x) = if (x mod 2 = 0) then x - 10 else x + 10
in
let val g = fn x => f(x + 2) * 2
in g(3)
end
end
The important bit is that the f(x + 2) part was not rewritten into g(x + 2) because val means that references to f are outer fs, not the f being defined, because a val is not a self-recursive definition. So any reference to an f within that definition would have to depend on it being available in the outer scope.
But the g(3) bit is rewritten because between in-end, the inner f (now g) is shadowing. So whether it's a fun or a val does not matter with respect to the shadowing of let-in-end.
(There are some more details wrt. val rec and the exact scope of a let val f = ... that I haven't elaborated on.)
As for your questions,
You should be able to answer this now. A nice way to provide the answer is 1) rename the inner function for clarity, 2) evaluate the code by hand using substitution (one rewrite per line, ~> denoting a rewrite, so I don't mean an SML operator here).
Here's an example of how it'd look with my second example (not your code):
g(3)
~> (fn x => f(x + 2) * 2)(3)
~> f(3 + 2) * 2
~> f(5) * 2
~> (if (5 mod 2 = 0) then 5 - 10 else 5 + 10) * 2
~> (if (1 = 0) then 5 - 10 else 5 + 10) * 2
~> (5 + 10) * 2
~> 15 * 2
~> 30
Your evaluation by hand would look different and possibly conclude differently.
What is tail recursion? Provide a definition and ask if your code satisfies that definition.
I'm not sure what you mean by rewriting it using static / dynamic allocation. You'll have to elaborate.
How can I define an outer constructor that has same number of arguments as the field values? What I want to do is something like this:
struct data
x
y
end
function data(x, y)
return data(x-y, x*y)
end
But it obviously causes stackoverflow.
Based on the various helpful comments, thanks to all, I changed my answer. Here is an example in Julia 1.0.0 of what you may be after. I am learning Julia myself, so maybe further comments can improve this example code.
# File test_code2.jl
struct Data
x
y
Data(x, y) = new(x - y, x * y)
end
test_data = Data(105, 5)
println("Constructor example: test_data = Data(105, 5)")
println("test_data now is...: ", test_data)
#= Output
julia> include("test_code2.jl")
Constructor example: test_data = Data(105, 5)
test_data now is...: Data(100, 525)
=#
This works for me
julia> struct datatype
x
y
end
julia> function datatype_create(a,b)
datatype(a - b, a * b)
end
datatype_create (generic function with 1 method)
julia> methods(datatype_create)
# 1 method for generic function "datatype_create":
[1] datatype_create(a, b) in Main at none:2
julia> methods(datatype)
# 1 method for generic function "(::Type)":
[1] datatype(x, y) in Main at none:2
julia> a = datatype_create(105,5)
datatype(100, 525)
julia> b = datatype_create(1+2im,3-4im)
datatype(-2 + 6im, 11 + 2im)
julia> c = datatype_create([1 2;3 4],[4 5;6 7])
datatype([-3 -3; -3 -3], [16 19; 36 43])
julia> d = datatype_create(1.5,0.2)
datatype(1.3, 0.30000000000000004)
If you are absolutely Ideologically Hell Bent on using an outer constructor, then you can do something like this
julia> datatype(a,b,dummy) = datatype(a - b,a * b)
datatype
julia> e = datatype(105,5,"dummy")
datatype(100, 525)
Antman's solution using the power of MACRO
julia> macro datatype(a,b)
return :( datatype($a - $b , $a * $b) )
end
#datatype (macro with 1 method)
julia> f = #datatype( 105 , 5 )
datatype(100, 525)
Is there a way to get the surface syntax AST of a method?
according to the docs http://docs.julialang.org/en/stable/devdocs/reflection/ there is a function/macro for everything below surface AST, starting with code_lowered for lowered AST.
it would be great to have something like
f(a,b) = 2*a + b
#code_surface f(1,2)
# :(2a + b)
where code_surface shall return f's definition in form of a standard Expr abstract syntax tree.
#code_expr from CodeTracking.jl returns the Expr of the method definition (needs the Revise.jl package to also be installed).
julia> f(a,b) = 2*a + b
f (generic function with 1 method)
julia> using CodeTracking
julia> #code_expr f(1, 2)
:(f(a, b) = begin
#= REPL[65]:1 =#
2a + b
end)
julia> #code_string f(1, 2)
"f(a,b) = 2*a + b"
(There was discussion about adding a similar feature to base Julia, but it seems unlikely to happen at this point.)
Having the LHS of the method definition in the result helps with knowing which method was applied to the given arguments
julia> f(a::String,b::String) = a * b
f (generic function with 2 methods)
julia> #code_expr f("hi", " friend")
:(f(a::String, b::String) = begin
#= REPL[74]:1 =#
a * b
end)
julia> #code_expr f(2, 5)
:(f(a, b) = begin
#= REPL[65]:1 =#
2a + b
end)
But if you only need the Expr of the function body, you can extract that part of the expression from the result (ex = #code_expr(f(2, 5)); ex.args[2]).