Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I resolve the scope of variables in a julia expression?

Tags:

julia

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

like image 524
Mason Avatar asked Oct 07 '20 21:10

Mason


People also ask

How will you refer scope of the variable?

A scope is a region of the program and broadly speaking there are three places, where variables can be declared: Inside a function or a block which is called local variables, In the definition of function parameters which is called formal parameters. Outside of all functions which is called global variables.

What is :: In Julia?

A return type can be specified in the function declaration using the :: operator. This converts the return value to the specified type. This function will always return an Int8 regardless of the types of x and y .


1 Answers

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}:
  :+
  :*
  :-
  :^
like image 170
Mason Avatar answered Sep 20 '22 00:09

Mason