I've been trying to get my head around shallow binding and deep binding, wikipedia doesn't do a good job of explaining it properly. Say I have the following code, what would the output be if the language uses dynamic scoping with
a) deep binding
b) shallow binding?
x: integer := 1
y: integer := 2
procedure add
x := x + y
procedure second(P:procedure)
x:integer := 2
P()
procedure first
y:integer := 3
second(add)
----main starts here---
first()
write_integer(x)
Deep binding binds the environment at the time the procedure is passed as an argument
Shallow binding binds the environment at the time the procedure is actually called
So for dynamic scoping with deep binding when add is passed into a second
the environment is x = 1, y = 3 and the x is the global x so it writes 4 into the global x, which is the one picked up by the write_integer.
Shallow binding just traverses up until it finds the nearest variable that corresponds to the name so the answer would be 1.
a) In deep binding we deal with the environment of add, in which x refers to the global x and y refers to the y local to first (the last executed function which has a declaration of y)
x (global) = x (global) + y (local) : x = 1 + 3 = 4
b) In shallow binding, we deal with the environment of second, in which x refers to the x local to second and y refers to the y local to first (the last executed function which has a declaration of y)
x (local) = x (local) + y (local) : x = 2 + 3 = 5
BUT : write_integer(x) outputs the global x which is equal to 1
Finally
a) 4
b) 1
shallow binding should be 5.
definations:
http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=15&lngWId=6
Related
In Julia 1.0.5, I have a function f(x::Vector{<:Real}), defined as
f(x::Vector{<:Real}) = (x[1] - 2)^2 + ( x[2] - 1 )^2
The signature is like this, because I would like to use it with the ForwardDiff package, and it works with it just fine. I give the function to ForwardDiff.gradient, and everything works like a charm.
However, I would also like to do some visualizations with PyPlot, using this same function f. Namely, I would like to draw its contour with contourf. For this purpose, I have constructed two vectors X::Vector{<:Real} and Y::Vector{<:Real}, and would like to call the same function f with them to produce the contour.
However, making the call f.([X, Y]) is not broadcasting the vectors as I would like, as I get the error
LoadError: MethodError: no method matching (::getfield(Main, Symbol("#f#1044")))(::Int64)
Closest candidates are:
f(!Matched::Array{#s25,1} where #s25<:Real)
This of course prevents me from using the contourf function, as it needs the values of f on a 2D-grid.
Do I need to define an entirely different f(x::Vector{<:Real}, y::Vector{<:Real}) to be able to plot the contour as I would like, or is there an alternative where I can avoid this?
this problem can be resolved by the power of multiple dispatch:
f(x::Vector{<:Real}) = (x[1] - 2)^2 + ( x[2] - 1 )^2
f(x::Real,y::Real) = f([x,y])
nx = 10
ny = 20
X = rand(nx) #mesh of x points
Y = rand(ny) #mesh of y points
Z = f.(transpose(X),Y) #nx x ny matrix
for the two argument gradient:
two_point_gradient(f,x,y) = ForwardDiff.gradient(f,[x,y])
G = two_point_gradient.(f,transpose(X),Y) #returns a vector of gradients, where G[i..] = gradient(f,X[i..],Y[i...])
In Julia, I know of three ways to define a named multiline function:
1.
function f(x, y)
...
end
2.
f = function(x, y)
...
end
3.
f(x, y) = begin
...
end
They all seem to produce the same outcome.
Is there any difference? Which one should be used and why?
1 and 3 are functionally identical, but 1 is preferred stylistically. The "short form function declaration" f(x,y) = … is typically used (and encouraged) for one-line definitions — that is, without a begin block.
2 is different. It's creating an anonymous function, and then assigning it to f. Note that unlike the bindings created by 1 and 3, you can actually reassign f to completely different things. This means that Julia cannot assume that f will always call that function, which means that it cannot do any of its normal optimizations. Now, if you used const f = function(x, y) …, then f is a constant binding and it should behave similarly to the other declarations. But note that f is still just a binding to an anonymous function — the function itself doesn't know what its name is! So it'll print as #1 (generic function with 1 method) instead of f (generic function with 1 method).
See https://docs.julialang.org/en/stable/manual/functions/ for more details.
Definitions 1 and 3 are equivalent (the difference is only style, option 1 is usually preferred). They define function f for which you can implement multiple methods (https://docs.julialang.org/en/v1/manual/methods/).
Definition 2 creates an anonymous function and assigns it to a global variable f. I would not encourage it in general.
If you would call such a function inside other function using name f the result would not be type stable (variable f from global scope would have to be resolved). Anonymous functions are usually used in situations where the name is not important.
Actually there are two other ways to define multiple line anonymous function (again - I do not encourage it but show it for completeness):
f = x -> begin
...
end
and
f = identity() do x
...
end
I am studying for a final, and I have a practice problem here.
The question asks for the result of
val y = ref 1;
fun f x = (!y) + (x + x);
(f (y := (!y)+1; !y)) + (!y);
under the following parameter passing techniques:
Call by value
Call by name
Call by need.
It seems to me that for call by value, the answer is 8.
However, I believe the answer for call by name is also 8, but I would expect it to be different. The reason I think it is 8:
y := (!y)+1 derefs y as 1, adds 1, and then sets y to 2
!y in line 3 serves as the argument to f, and since it is being dereferenced it is
passed as a value rather than as a reference (this may be where I am
going wrong?)
The function call returns 6, but does not set y as y was passed in as a value from the previous step
6 is added to the dereferenced value of y, which is 2.
This returns 8
Is this the correct answer, and if not, can someone please point out where I have gone wrong? Also, can someone explain to me how call by need would work in this situation also?
Many thanks.
I found out how it works:
(y := (!y)+1; !y) is the parameter passed to f.
f then looks like:
fun f x = (!y) + ((y:= (!y)+1; !y) + (y:= (!y)+1; !y));
so this ends up being 1+2+3, and the final step + (!y) adds 3 as this is the current value of y, giving 9.
Thanks for pointing out that I was still doing call-by-value.
I can't seem to find a simple answer to this seemingly simple SML question. I have the code:
fun inde(x, y, L) = if null L then nil else
if x=hd(L) then y+1::inde(x,y+1,tl L) else
inde(x,y+1,tl L);
I want y to be a variable outside the function, so it'll be inde(x,L) but have the y still count properly. When I declare it outside the function (to 0), when the function is recursively called, it resets to 0.
If you were to run this current function, it'd produce a list of where ever x is in the list (L).
so inde(1,0,[1,2,2,1,1]) would produce [1,4,5]
Idiomatic structure when using a functional programming style is to define an inner function that takes arguments that are of interest to the programmer, but not the user and then to call the inner function from the main function:
fun inde(x : int, L) =
let
fun inner(list1, list2, y : int) =
if null list1
then List.rev list2
else
if x = hd list1
then
inner(tl list1, y::list2, y + 1)
else
inner(tl list1, list2, y +1)
in
inner(L,[],1)
end
In the example function:
inner uses four values: the local variables list1,list2, and y. It also uses x from the enclosing scope.
inner builds (conses up) the list that will be returned using list2. It reverses the list with a call to List.rev from the SML Basis Library. This adds O(n) to the execution time.
The last part of the let...in...end construct: inner(L,[],1) is called "the trampoline" because the code gets all the way to the bottom of the source file and then bounces off it to start execution. It's a standard pattern.
Note that I started iterating with y equal to 1, rather than 0. Starting at zero wasn't getting anything done in the original file.
I have this question :
The program is very simple :
sub(b, a)
<=>
sub(x, y)
x = x + y = 3 + 2 = 5
y = x + y = 5 + 2 = 7
<=>
b = 5
a = 7
therefore d is the right answer
but the given answer is c(a = 7, b =3 )
Why? What am i missing here ?
Any help is greatly appreciated !
Note that "the parameter x is called by value, and the parameter y is called by reference".
So b is passed by value, which means that the x inside sub is just a local variable - it's not pointing to the same location as b.
Therefore, the changes made to x inside sub do not affect the variable b that was passed in.
Contrast with y which is passed by reference, which means that y and a are actually the same variable, so changes to y inside sub are reflected in a outside of it.
The trick here is the difference between pass-by-value and pass-by-reference. As the prompt notes x is passed (or "called") by value. This means that when you pass b to sub as x, x contains only the literal value of b. What this means from a practical standpoint is that any changes made to x in sub will NOT affect b back in the main program.
On the other hand, since y is passed by reference, when you pass a to sub as y, y is really a reference to the variable a (y "points" to a). This means that if you make changes to y in sub those changes affect a back in the main program.
If the above is confusing to you, think of it this way: if a variable is passed by value to a function, you can replace the parameter name (x) with the value of the argument (3). If a variable is passed by reference to a function, you can think of it as replacing the parameter name (y) with the variable name of the argument (a).
With that in mind, let's revisit the question:
a = 2;
b = 3;
sub(b, a);
----------
x = x + y
(in this line x represents the value of b, which is 3, so the value of x (but not b) is now 5)
y = x + y
(in this line y represents the actual variable a, whose value is 3. When we add x to y, however, it actually changes a. Therefore, the value of both y and a after this line is 7)
return;
So as you can see, b cannot be changed in the original function, so its final value can only be 3. a however can be changed, and due to operations in sub now has a value of 7.
I hope this clears up any confusion you were facing with this problem.