scope of Julia variable with if block nested in for loop - julia

for i=1:5
if(i==1)
z = i
end
println("i = $i, z = $z")
end
i = 1, z = 1
ERROR: UndefVarError: z not defined
Stacktrace:
[1] top-level scope at ./REPL[6]:5 [inlined]
[2] top-level scope at ./none:0
The behavior of the above script is puzzling to me. Can someone help me understand why the print works when i=1 but fails when i=2.

The answer by #Wookies-Will-Code is correct and here is the reason.
As the Julia manual explains here:
for loops, while loops, and Comprehensions have the following behavior: any new variables introduced in their body scopes are freshly allocated for each loop iteration
Which means that at the end each iteration z is forgotten.
In order to make sure the value of z is persistent across iterations (and also after for loop finishes) define z before the loop. For example like this:
function mytest()
local z
for i=1:5
if i==1
z = i
end
println("i = $i, z = $z")
end
end
and now you have:
julia> mytest()
i = 1, z = 1
i = 2, z = 1
i = 3, z = 1
i = 4, z = 1
i = 5, z = 1
Observe that the situation is different in global scope. Even if z is globally defined it is not reused by default:
julia> z = 100
100
julia> for i=1:5
if i==1
z = i
end
println("i = $i, z = $z")
end
i = 1, z = 1
ERROR: UndefVarError: z not defined
Stacktrace:
[1] top-level scope at .\REPL[7]:5 [inlined]
[2] top-level scope at .\none:0
The reason is that Julia treats z as local to the for loop, because z is assigned to inside the loop. This is a compile time feature check so even if the if condition always fails you will get this error:
julia> z = 100
100
julia> for i=1:5
if false
z = i
end
println("i = $i, z = $z")
end
ERROR: UndefVarError: z not defined
Stacktrace:
[1] top-level scope at .\REPL[18]:5 [inlined]
[2] top-level scope at .\none:0
You have to assign to z using global keyword to make it work:
julia> z = 100
100
julia> for i=1:5
if i==1
global z = i
end
println("i = $i, z = $z")
end
i = 1, z = 1
i = 2, z = 1
i = 3, z = 1
i = 4, z = 1
i = 5, z = 1

I do not use Julia, but here goes. I am not sure how to send the string that z is not defined, but here 2 different prinln based on the value of i, simplest way to do it, or else you have to check if z is defined, this is simpler.
for i=1:5
if(i==1)
z = i
println("i = $i, z = $z")
else
println("i = $i","z not defined")
end
end

Related

Declare multiple variable bindings in one line in SML

Is it possible to declare multiple variable bindings in one line in SML? For example, I have the following:
let
val m1 = [1]
val m2 = [2]
val m3 = [3]
in
{...}
end
I would like to condense this down to something like
let
val m1 = [1], m2 = [2], m3 = [3]
in
{...}
end
This syntax doesn't work, but is there a way to declare multiple variable bindings in one line like this?
Here are two ways:
- let val x = 1 val y = 5 in x + y end;
val it = 6 : int
- let val x = 1 and y = 5 in x + y end;
val it = 6 : int
I personally find the slight abuse of and more readable.
However, I think the "destructuring bind" method is more common than either of these, since it's also more generally useful.
- let val (x, y) = (1,5) in x + y end;
val it = 6 : int
- fun f x = (x, x + 2, x + 3);
val f = fn : int -> int * int * int
- let val (x, y, z) = f 3 in x + z end;
val it = 9 : int
You could create a tuple and immediately destructure it.
let
val (m1, m2, m3) = ([1], [2], [3])
in
...
end

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

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}:
:+
:*
:-
:^

Outer constructor that has the same number of arguments as the field values

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)

Generate a symbolic interpolating polynomial in Scilab

I've made a code to calculate the result of divided differences method and lagrange method by interpolating points. I would also like to build a polynomial using symbolic variables but how can I accomplish this?
function dividedDifferences(X,Y,x)
ddMatrix = X'
ddMatrix(:,2) = Y'
for j=3:length(Y)+3
for i=1:length(Y)+2-j
ddMatrix(i,j) = (ddMatrix(i,j-1)-ddMatrix(i+1,j-1))/(ddMatrix(i,1)-ddMatrix(i+j-2,1))
end
end
disp(ddMatrix)
Px = 0
for j=2:length(Y)+1
prd = 1
for i=1:j-2
prd = prd * (x - ddMatrix(i,1))
end
Px = Px + ddMatrix(1,j)*prd
end
disp(Px)
endfunction
function lagrange(X,Y,x)
for i=1:length(Y)
l(i)=1
for j=1:length(Y)
if i~=j
l(i) = l(i)*(x-X(j))/(X(i)-X(j))
end
end
end
disp(l')
L=0
for i=1:length(Y)
L = L+Y(i)*l(i)
end
disp(L)
endfunction
//example instance
X = [0 1 5 8]
Y = [0 1 8 16.4]
x = 7
dividedDifferences(X,Y,x)
lagrange(X,Y,x)
To create a symbolic polynomial, initialize a symbolic variable with x = poly(0,"x") where x is the name of the variable to use in the polynomial. Then proceed to compute with it exactly as you did in the function lagrange. I essentially copied your function to symboliclagrange below, cutting out the numerical parameter and intermediate display:
function symboliclagrange(X,Y)
x = poly(0,"x")
for i=1:length(Y)
l(i)=1
for j=1:length(Y)
if i~=j
l(i) = l(i)*(x-X(j))/(X(i)-X(j))
end
end
end
L=0
for i=1:length(Y)
L = L+Y(i)*l(i)
end
disp(L)
endfunction
With your input X = [0 1 5 8], Y = [0 1 8 16.4] the output is 0.85x+0.15x2, which is the correct interpolating polynomial.

Difference in local & let scoping rule?

In the following example:
Fs = cell(2)
i = 1
for i = 1:2
local i # same as local i = i
Fs[i] = () -> i
end
println(Fs[1]()) # 1
println(Fs[2]()) # 2
println(i) # 1
Is it true that local i is the same as local i = i?
Why cannot I do the same for while loop as such?
Fs = cell(2)
i = 1
while i <= 2 #LoadError: UndefVarError: i not define
local i = i
Fs[i] = ()->i
i += 1
end
But have to use let:
Fs = cell(2)
i = 1
while i <= 2
let i = i
Fs[i] = ()->i
end
i += 1
end
println(Fs[1]()) # 1
println(Fs[2]()) # 2
When you introduce new variable, and try to get it's value before assignment, Julia throws an UndefVarError error, in the first example:
Fs = cell(2)
i = 1
for i = 1:2
local i # same as local i = i
Fs[i] = () -> i
end
println(Fs[1]()) # 1
println(Fs[2]()) # 2
println(i) # 1
For block introduces a new local i, adn for command itself assign it so the code successfully dose it's duty. But in the second example:
Fs = cell(2)
i = 1
while i <= 2 #LoadError: UndefVarError: i not define
local i = i
Fs[i] = ()->i
i += 1
end
A new i was introduced in while block, but before assignment you try to get it's value, and this produces an error.
In 3d one let command declare a new local block and a new i variable for it's block.
julia> function test3()
Fs = cell(2)
i = 1
while i <= 2
let i = 100
println(i)
end
i += 1
end
println(i)
end
test3 (generic function with 1 method)
julia> test3()
100
100
3# while block use the function's scope

Resources