can someone please explain why is "ans" is bound to value of 16 in here after evaluation - this is a correct answer?
I thought the answer 3 since we're calling function f and sending values 1 and 2 as function f doesn't also see the values 5 and 10 but I guess I am wrong.
val x = 1
val y = 2
val f = fn y => x + y
val x = 5
val y = 10
val ans = f x + y
I think I figured it out. Here goes:
The function f doesn't get evaluated until the end. So at:
val ans = f x + y
... the function f gets called with the recent value x which is 5 because the value of the previous x is being shadowed. So at:
val f = fn y => x + y
... the value received becomes the value of y. and here the function f takes the value the previous x which is 1 so that's a total of 6 (x comes from static environment). Then:
val ans = f x + y
we get back here: 6 + 10 = 16
What you are seeing is sometimes called lexical scoping. The function f was defined in the scope of a certain binding for x, that scope is the only scope that matters in understanding what f does when f is invoked. The fact that x has a different meaning in the scope in which f is invoked doesn't affect the meaning of f itself. In the context of functional programming anything else would violate referential transparency. In the scope of a binding such as
val x = 1
it should be possible to freely replace x by 1. Thus your definition of f should be equivalent to the definition:
def f y = 1 + y
as, indeed, it is.
Related
A variable p exists, it is created by a foreign package. I think it is a pointer to W1, which is created by me in the global scope.
typeof(p) # output: GlobalRef
p # output: :(Main.W1)
p.name # output: :W1
p.mod # output: Main
How can I retrieve W1, which is the value behind p?
In other words, is there a function f for which W1 === f(p)?
Some context for the interested: I'm trying to optimize a Neural Network and loss (together represented by the function loss) using vanilla Zygote:
for s in 1:100
l = 0.
gs = gradient(Zygote.Params(optimizable_params)) do
l = loss(X[s, :], y[s])
end
push!(losses, l)
for (p, g) in pairs(gs.grads)
p += η * g # Here the p is coming from
end
end
It seems like that this particular use-case is a mistake. However, in general you can get the object being referred to like this:
julia> module X
x = 5
end
Main.X
julia> g = GlobalRef(X, :x)
:(Main.X.x)
julia> getfield(g.mod, g.name)
5
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.
This question already has answers here:
Value of bindings in SML?
(2 answers)
Closed 6 years ago.
Could someone please help. I don't get the sequence of evaluation here and how we got values of "ans". e.g. in the first example there's no value of y and I'm not sure whether this returns a pair or calls x ! (fn y => y x). It would be very helpful if you can Trace each expression.
val x = 1
val f = (fn y => y x)
val x = 7
val g = (fn y => x - y)
val ans = f g
val ans = 6 : int
=====================================
fun f p =
let
val x = 3
val y = 4
val (z,w) = p
in
(z (w y)) + x
end
val x = 1
val y = 2
val ans = f((fn z => x + z), (fn x => x + x + 0))
val ans = 12 : int
There are a few things which help make problems like this much clearer
when trying understand an alien function Lexical scoping works.
add in types to the parameters and return values without modifying the program, the compiler will tell you if you get it wrong...
replace anonymous functions with named ones.
rename variable bindings that have the same names but refer to different lexical scope.
remove variable bindings that only get used once.
binding a value to a name does not actually perform any computation,
so is merely for the benefit of the reader, if it is not doing that job
it merely serves to obfuscate, then by all means remove it.
fun f (y1 : int -> 'a) = y1 1 : 'a;
fun g (y2 : int) = 7 - y2 : int;
val ans : int = f g;
so g is given as a parameter to f, f calls g giving it the parameter x having the value 1 making y2 = 1, which g subtracts 7 - 1 returning 6.
the return value of g is an int, thus f's 'a type when g is applied to it is an int.
for the 2nd one clean it up a bit, I pulled the anonymous fn's out into their own and named values and call f (foo, bar) to make it more readable...
fun f p =
let val x = 3
val y = 4
val (z, w) = p
in (z (w y)) + x end
fun foo z = z + 1;
fun bar x = x * 2;
val ans = f(foo, bar);
Finally, we can get rid of the let values which are only used once
and replace the (z,w) = p with just (z, w) as a parameter to the function which should be much easier to follow
fun f (z, w) = (z (w 4)) + 3
fun foo z = z + 1;
fun bar x = x * 2;
val ans = f(foo, bar);
val ans = ((4 * 2) + 1) + 3
I know that let rec is used when I want recursive.
For example,
let rec power i x = if i = 0 then 1.0 else x *. (power (i-1) x);;
Ok, I understand that.
But how about this one:
let x y = y + y in x 2?
Should I use rec inside?
I think I should, because it has x 2 inside, loading itself, but it seems it is fine with compiler.
So when I should use let rec and shouldn't?
Also, what is the difference between
let (-) x y = y - x in 1-2-3;;
and
let rec (-) x y = y - x in 1-2-3;;
Are they both legal?
You need to understand the scoping rules of OCaml first.
When you write let f XXX = YYY in ZZZ, if you use f in YYY then you need rec. In both cases (ie with or without rec),f will be defined in ZZZ.
So:
let x y = y + y in
x 2
is perfectly valid.
For you second question: no it is not equivalent, if you try it on the toplevel, the second statement loop for ever and is equivalent to let rec loop x y = loop y x in (). To understand why it is looping for ever, you can understand the application of loop as an expansion where the identifier is replaced by its body. so:
So loop body is function x y -> loop y x, which can be expanded to
function x y -> (function a b -> loop b a) y x (I've renamed the parameter names to avoid ambiguity), which is equivalent to function x y -> loop x y when you apply the body and so on and so on. So this function never does anything, it just loops forever by trying to expand/apply its body and swapping its arguments.
let (++) f g x = f (g x) in
let f x = x + 1 in
let g x = x * 2 in
(f++g) 1;;
Is the above expression correct?
It seems to me that the above code should be just like defining f++g x = 2 * x + 1. Am I correct?
Your implementation of function composition is correct, since :
(g ∘ f)(x) = g(f(x)) for all x in X
according to wikipedia
I get :
- : int = 3
in ocamlktop