What does it mean to declare a 'local' variable inside a 'let'? - cairo-lang

As I understand it, let defines a reference, which can be seen as an alias, so for example let x = y * y * y doesn't compute y * y * y but the occurrences of x will be replaced by y * y * y.
Local variables are similar to other languages local variables.
As in https://www.cairo-lang.org/docs/hello_cairo/dict.html, what does it mean to write let (local dict_start : DictAccess*) = alloc()? That every instance of local dict_start : DictAccess* will be replaced by alloc()? Why not just local (dict_start : DictAccess*) = alloc() or let (dict_start : DictAccess*) = alloc()?

First note that when a function is called, the returned values are placed in memory, so e.g. in the case of alloc which returns a single value, the return value can be found in [ap-1] (you can read more about the stack structure and function calls here).
let (dict_start : DictAccess*) = alloc() is actually valid, and is a syntactic sugar for the following:
alloc()
let dict_start = [ap-1]
let (local dict_start : DictAccess*) = alloc() is equivalent to:
alloc()
let dict_start = [ap-1]
local dict_start = dict_start
In the last line, I substitute the value referenced by dict_start value into a local variable, and rebind the reference dict_start to the location of the local variable. The motivation to use this might be to avoid potential revocations (which may be solved by putting the return value in a local variable). This is probably what you want to do with local (dict_start : DictAccess*) = alloc(), which is simply not supported by the current version of the compiler.

Related

Binding vs Assignment

I've read a number of articles on the difference between assignment and binding, but it hasn't clicked yet (specifically in the context of an imperative language vs one without mutation).
I asked in IRC, and someone mentioned these 2 examples illustrate the difference, but then I had to go and I didn't see the full explanation.
Can someone please explain how/why this works in a detailed way, to help illustrate the difference?
Ruby
x = 1; f = lambda { x }; x = 2; f.call
#=> 2
Elixir
x = 1; f = fn -> x end; x = 2; f.()
#=> 1
I've heard this explanation before and it seems pretty good:
You can think of binding as a label on a suitcase, and assignment as a
suitcase.
In other languages, where you have assignment, it is more like putting a value in a suitcase. You actually change value that is in the suitcase and put in a different value.
If you have a suitcase with a value in it, in Elixir, you put a label on it. You can change the label, but the value in the suitcase is still the same.
So, for example with:
iex(1)> x = 1
iex(2)> f = fn -> x end
iex(3)> x = 2
iex(4)> f.()
1
You have a suitcase with 1 in it and you label it x.
Then you say, "Here, Mr. Function, I want you to tell me what is in this suitcase when I call you."
Then, you take the label off of the suitcase with 1 in it and put it on another suitcase with 2 in it.
Then you say "Hey, Mr. Function, what is in that suitcase?"
He will say "1", because the suitcase hasn't changed. Although, you have taken your label off of it and put it on a different suitcase.
After a while, I came up with the answer that is probably the best explanation of the difference between “binding” and “assignment”; it has nothing in common with what I have written in another answer, hence it’s posted as a separate answer.
In any functional language, where everything is immutable, there is no meaningful difference between terms “binding” and “assignment.” One might call it either way; the common pattern is to use the word “binding,“ explicitly denoting that it’s a value bound to a variable. In Erlang, for instance, one can not rebound a variable. In Elixir this is possible (why, for God’s sake, José, what for?)
Consider the following example in Elixir:
iex> x = 1
iex> 1 = x
The above is perfectly valid Elixir code. It is evident, one cannot assign anything to one. It is neither assignment nor binding. It is matching. That is how = is treated in Elixir (and in Erlang): a = b fails if both are bound to different values; it returns RHO if they match; it binds LHO to RHO if LHO is not bound yet.
In Ruby it differs. There is a significant difference between assignment (copying the content,) and binding (making a reference.)
Elixir vs Ruby might not be the best contrast for this. In Elixir, we can readily "re-assign" the value of a previously assigned named variable. The two anonymous-function examples you provided demonstrate the difference in how the two languages assign local variables in them. In Ruby, the variable, meaning the memory reference, is assigned, which is why when we change it, the anonymous function returns the current value stored in that memory-reference. While in Elixir, the value of the variable at the time the anonymous function is defined (rather than the memory reference) is copied and stored as the local variable.
In Erlang, Elixir's "parent" language, however, variables as a rule are "bound." Once you've declared the value for the variable named X, you are not allowed to alter it for the remainder of the program and any needed alterations would need to be stored in new named variables. (There is a way to reassign a named variable in Erlang but it is not the custom.)
Binding refers to particular concept used in expression-based languages that may seem foreign if you're used to statement-based languages. I'll use an ML-style example to demonstrate:
let x = 3 in
let y = 5 in
x + y
val it : int = 8
The let... in syntax used here demonstrates that the binding let x = 3 is scoped only to the expression following the in. Likewise, the binding let y = 5 is only scoped to the expression x + y, such that, if we consider another example:
let x = 3 in
let f () =
x + 5
let x = 4 in
f()
val it : int = 8
The result is still 8, even though we have the binding let x = 4 above the call to f(). This is because f itself was bound in the scope of the binding let x = 3.
Assignment in statement-based languages is different, because the variables being assigned are not scoped to a particular expression, they are effectively 'global' for whatever block of code they're in, so reassigning the value of a variable changes the result of an evaluation that uses the same variable.
The easiest way to understand the difference, would be to compare the AST that is used by the language interpreter/compiler to produce machine-/byte-code.
Let’s start with ruby. Ruby does not provide the AST viewer out of the box, so I will use RubyParser gem for that:
> require 'ruby_parser'
> RubyParser.new.parse("x = 1; f = -> {x}; x = 2; f.()").inspect
#=> "s(:block, s(:lasgn, :x, s(:lit, 1)),
# s(:lasgn, :f, s(:iter, s(:call, nil, :lambda), 0, s(:lvar, :x))),
# s(:lasgn, :x, s(:lit, 2)), s(:call, s(:lvar, :f), :call))"
The thing we are looking for is the latest node in the second line: there is x variable inside the proc. In other words, ruby expects the bound variable there, named x. At the time the proc is evaluated, x has a value of 2. Hence the the proc returns 2.
Let’s now check Elixir.
iex|1 ▶ quote do
...|1 ▶ x = 1
...|1 ▶ f = fn -> x end
...|1 ▶ x = 2
...|1 ▶ f.()
...|1 ▶ end
#⇒ {:__block__, [],
# [
# {:=, [], [{:x, [], Elixir}, 1]},
# {:=, [], [{:f, [], Elixir}, {:fn, [], [{:->, [], [[], {:x, [], Elixir}]}]}]},
# {:=, [], [{:x, [], Elixir}, 2]},
# {{:., [], [{:f, [], Elixir}]}, [], []}
# ]}
Last node in the second line is ours. It still contains x, but during a compilation stage this x will be evaluated to it’s currently assigned value. That said, fn -> not_x end will result in compilation error, while in ruby there could be literally anything inside a proc body, since it’ll be evaluated when called.
In other words, Ruby uses a current caller’s context to evaluate proc, while Elixir uses a closure. It grabs the context it encountered the function definition and uses it to resolve all the local variables.

What is the difference of immutable and mutable variables?

I have read almost every definition of immutable/mutable variables on the internet but as a beginner I just do not grasp it fully so I was wondering if someone could really explain it in layman terms.
Immutable variables (or objects) in any programming language is what I understand when you cannot change the value of that variable after it has been assigned a value. For example, I am using the Haskell programming language, and I write:
let x = 5
Since Haskell has immutable variables, x can never have any other value than 5. So if I after that line of code write:
x = 2
I have in fact not changed the value of x but made a new variable with the same name, which will now be the one that is referenced when I call x, so after both lines of code I can only reach an x with the value of 2.
But what is a mutable variable then, and what programming languages have it? This is where it gets foggy for me. Because when people say mutable variable, they are obviously referring to a variable or object which value you can indeed change after it has been assigned an initial value.
Does this mean that if you have a mutable variable you actually manipulate that place in the computers memory for that variable, and in case of immutable variable you cannot manipulate that place in the computers memory or what?
I don't know how to explain my question any further, as I said, I understand that mutable = can change value of variable after initial value assignment, immutable = cannot. I get the definition. But I don't understand what it actually means in terms of what is going on "behind the scenes". I guess I am looking for easy examples on actual mutable variables.
This has nothing to do with immutability
let x = 5
x = 2
This is reassignment and definitely not allowed in Haskell
First let's look at a regular let assignment
Prelude> let x = 5 in x
5
it :: Num a => a
You can bind x using let, and rebind a new x in a nested let – this effectively shadows the outer x
Prelude> let x = 5 in let x = 2 in x
2
it :: Num a => a
Remember a let is basically a lambda
Prelude> (\x -> x) 5
5
it :: Num a => a
And of course a lambda can return a lambda; illustrates shadowing agian
Prelude> (\x -> (\x -> x)) 5 2
2
it :: Num a => a
I believe a shorthand answer to your question would be that a Mutable variable that holds a value that you would later want to be adjusted.
Depending on the language you're using is its method.
In Kotlin val and var are used to declare variables.
val is a constant while var is adjustable.
Mutable respectively immutable does not concern the variables but the values. Note: one also says the type is (im-)mutable.
For instance if the value is of an immutable type StudentCard, with fields ID and Name, then after creation the fields no longer can be changed. On a name change the student card must be reissued, a new StudentCard must be created.
A more elementary immutable type is String in java. Assigning the same value to two variables is no problem as one variable may not change the shared value. Sharing a mutable value could be dangerous.
A commont mutable type is the array in java and others. Sharing an array, say storing an array parameter in a field, risks that somewhere else the array content is changed inadvertently changing your field.

Block does not recognise variable at first time

y = lambda { z }
z = 9
y.call
=> NameError: undefined local variable or method `z' for main:Object
y = lambda { z }
y.call
=> 9
I thought the idea of having a block was defer the execution of the piece of code inside the block. Can you explain this?
lambda creates what's known as a lexical closure, which means it captures a reference to the enclosing environment and can use variables that are in scope at the time the closure is created.
y = lambda { z } # Woops! There's no variable named `z`!
It doesn't matter if you create a variable named z after creating the closure; the idea of the closure is that it captures the environment at that particular moment.
In theory, you could hope for an error when you create that lambda, because it's possible to analyze it and determine that a variable will be dereferenced which has not been defined. Ruby doesn't work that way, however; it is only when code is being evaluated that you get an error for attempting to access an undefined variable.
When you create a second closure, a few lines later, that one does capture an environment in which z exists:
y = lambda { z } # This closure is broken and can't be fixed
z = 9
y = lambda { z } # This is a new closure, and `z` is accessible within it
I thought the idea of having a block was defer the execution of the piece of code inside the block.
Sort of, but it's not the same as simply copying and pasting the code from the lambda and evaluating it when you call it. evaling a string would do that:
y = "z"
z = 9
eval(y)
# => 9
Again, the idea of a closure is that it captures both the code and the environment.
In the first line, when the block is created, there simply is no z yet that could be "catched" by the block yet. When you write y = lambda { z } the second time, there is a z.
The block takes a kind of snapshot of the surrounding variables. And in this case, no variable named z was present the first time.
When you define a lambda, it gets a closure, consisting of references to all the variables in scope at the time of definition. The lambda always has access to the current value of each variable it has "closed over", but newly defined variables aren't added to the closure retroactively. So when you do this:
x = 5
y = lambda { x + z }
z = 7
the lambda y has access to the value of x, but not z, because only x was in existence at the time you defined the lambda. But if you do this:
x = 5
z = 0
y = lambda { x + z }
z = 7
y.call
# => 12
then all will be well.
undefined local variable or method 'z' for main:Object comes when local variables are not created. local variables created by only assignment operation.
your first y = lambda { z } couldn't bind z as z is defined after this lambda definition.
the below works :
y = lambda { z }
y.call
=> 9
as you defined z = 9 before 2nd lambda definition.

Not fully evaluating in module?

How do I force evaluation of all symbols in a module?
vout[vin_] = Module[{x=vin,y},
y = 200000*(1.2 - x);
Print[y];
y
];
Print[vout[0]];
I'm expecting this to print the same thing (240000) twice, but instead I'm getting this:
200000*(1.2 - vin)
240000.
Any idea what to do here to be able to get the expanded value (240000) while within the module?
Edit: Print[Evaluate[y]]; will not work either in this case
you should type ":=" instead of "=", so that your function is recomputed correctly each time.
This works fine
vout[vin_] := Module[{x=vin,y},
y = 200000*(1.2 - x);
Print[y];
y
];
Print[vout[0]];

OCaml - For Loop inside If Statement

Coming from a Java and C background, grasping some concepts of Ocaml has been quite interesting. One such is, getting a/multiple statement to run inside a for loop.
let test_method (x:vector list)(vec:vector) =
if List.length x != 0 then
{a=0.;b=0.} (* Return a vector of 0,0 *)
else
for i = 0 to List.length x do
let key = {a=(List.nth x i).a;b=(List.nth x i).b}
done;;
the error that i get is done;; is an unexpected token. Why is this happening? this happens even if i do this
let test_method (x:vector list)(vec:vector) =
if List.length x != 0 then
{a=0.;b=0.} (* Return a vector of 0,0 *)
else
for i = 0 to List.length x do
let key = {a=(List.nth x i).a;b=(List.nth x i).b} in
let value = vec_neg key;
done;;
where vec_neg is a method that works fine that negates the vector type.
Any help would be greatly appreciated.
let expressions must have a body. (i.e. let var = val in body) (except let definitions at the top level of a module, which implicitly use the rest of the module as the body) let creates a local binding which is in scope inside the body. What's the point of doing that if you're not using it (i.e. don't have a body)? Plus every expression in the language has to evaluate to a value. A let expression evaluates to whatever the body evaluates to. That's why it needs a body.
After you wrote let foo = bar, you must write then in and write one more "assignment". Compiler expects in but encounters done, which is "unexpected".
You should remove let or add in, depending on what your aim is.

Resources