I have this statement:
let val x =
let val x = 5
in(fn y =>(y,x+y))
end
in
let val y=3 and z=10
in x z
end
end;
The output is :
(10,15)
I've been trying to track how this answer was produced but am getting confused. Is there a better way to write this that would help me understand what variables are being used where? Thank you!
First, some alpha-conversion:
let val fnPairOfInputAndInputPlus5 =
let val five = 5
in ( fn input => ( input, five + input ) )
end
in let val ignored = 3 and input = 10
in fnPairOfInputAndInputPlus5 input
end
end;
This code is demonstrating that when you declare a function value, unbound values in the declaring scope, such as the value five, are "enclosed" by the declaration (hence the term "closures"). Thus the function always returns a pair consisting of its input and its input plus five.
You could simplify it to
let fun f y = (y,5+y)
val y=3 and z=10
in
f z
end;
Note that the two instances of y are independent. The inner occurrence of x (which I've eliminated) is independent of the outer one (now renamed f).
Can be understood using manual evaluation with detailed explanations.
Starting with your initial expression:
let val x =
let val x = 5
in (fn y => (y,x + y))
end
in
let val y = 3 and z = 10
in x z
end
end;
Line 2,3,4 is an expression whose type is a function, as you see in the in part. It does not depends on any outer context, so it may be simplified as just fn y => (y, 5 + y), substituting x to 5, according to the binding given in let.
So you now have this:
let val x = fn y => (y, 5 + y)
in
let val y = 3 and z = 10
in x z
end
end;
After substitution of x (and removal of the let which in then now not necessary any more):
let val y = 3 and z = 10
in (fn y => (y, 5 + y)) z
end;
Note the y appearing in (y, 5 + y) are bound to the function's argument, and not to 3. There is no reference to this outer y, so its biding may be removed.
Now you have:
let z = 10
in (fn y => (y, 5 + y)) z
end;
Substituting z to 10 and removing the let which is not necessary any more, you get:
(fn y => (y, 5 + y)) 10;
This is a function application. You may evaluate it, to get:
(10, 5 + 10);
Which gives the final and constant result you noticed:
(10, 15);
Related
I would like to know the number of cases in which 1 dollar can be expressed in 1,5,10,20,50 cents.
For example, the count(100,[50,25]) is:
Because 50 * 1 + 25 * 2, it = 3:int is printed.
However, in my code, only the front part of the list is printed, so even if I count (100,[50,25]), it = 2:int is printed.
In other words, My code is not taking advantage of the whole list.
How do I solve this?
SML coin count function:
fun count(x,[]) = 0
| count (x,y::ys) =
let val cnt = 0
in if y*2 = x then cnt+2
else if y*4 = x then cnt + 4
else if y*10 = x then cnt + 10
else if y*10 = x then cnt + 10
else if y*20 = x then cnt + 20
else count(x-y,ys)
end;
Consider what happens as you evaluate your test expression of count (100, [50, 25]).
cnt is 0, y is 50, and ys is [25].
y times 2 does equal 100, so it returns cnt+2 which is 2. Nothing further happens.
When it comes to recursion, remember than the parameter list to a function is your means of communication. It seems like cnt is something that should be passed as a parameter so you can update it between recursive calls.
With count(x, []) = 0 you already have an exit point that will stop the recursion.
Edit: Based on comments, it looks like you're trying to figure out how many times each value in a list goes into a value x.
So the end result of your recursive function isn't a single integer. It's a list of integers. Or better yet, of tuples containing the value to look for, and the number of times it goes into x.
So if the list is empty, the result is obvious.
fun count(x, []) = []
It's an empty list. Otherwise, we need to append something onto a list.
fun count(x, []) = []
| count(x, y::ys) =
(y, x div y) :: count(x, ys)
Of course, we also have functions like map that basically do this for us.
fun count(x, lst) = List.map (fn y => (y, x div y)) lst
I saw let (-) x y = y - x in 1 - 2 - 3 and let rec (-) x y = y - x in 1 - 2 - 3 these two examples in a book about ocaml. When I saw the former one, I thought I understood the trick behind until I saw the latter function. It seems that the latter function is having some stack overflow problem, but why is it the case? How does ocaml evaluate these two expressions separately?
It might be helpful to rename the let bound functions.
let (-) x y = y - x
in 1 - 2 - 3
(* The above expression is equivalent to the following. *)
let f x y = y - x
in f (f 1 2) 3
(* Which reduces to the following. *)
let f x y = y - x
in 3 - (2 - 1)
Note that the function we defined, let (-) x y, is different from the function which we use in the definition, y - x. This is because let without rec doesn't bind the function name within the definition. Hence, the (-) operator in the definition is the native minus operator. Therefore, the result is 2.
Now, consider the second example.
let rec (-) x y = y - x
in 1 - 2 - 3
(* The above expression is equivalent to the following. *)
let rec f x y = f y x
in f (f 1 2) 3
Now, what does f 1 2 reduce to? It reduces to f 2 1, which reduces to f 1 2, which reduces to f 2 1, and so on ad infinitum. Now, in a language without tail call optimization this would result in a stack overflow error. However, in OCaml it should just run forever without returning.
The let expression has syntax is let <name> = <expr1> in <expr2> and it defines <name> to be bound to <expr1> in <expr2>. The <name> itself is not visible in the scope of <expr1>, in other words it is not recursive by default. And that feature could be (and often used) to give the same names the new meaning, e.g., this is the canonical OCaml code,
let example () =
let name = "Alice" in
let name = "Professor " ^ name in
print_endline name
The same technique approach is used in the let (-) x y = y - x in 1 - 2 - 3, where we redefine the (-) in terms of the original (-) operator which is still seen untouched in the scope of the y - x expression.
However, when we add the rec keyword to the let definition then the name is immediately visible in the scope of the currently defined expression, e.g.,
let rec (-) x y = y - x
(* ^ | *)
(* | | *)
(* +----------+ *)
here - in x - y refers to the currently defined function, so we have a recursive definition that says that x minus y is y minus x - a bogus definition.
the keword rec do not do anything and do not cause any segmentation fault
like this example
let rec x x=x+x in x 2;;
:-int=2
In this definition:
let rec x x = x + x
The "recursive" function name x is hidden by the parameter named x. It's just as if you had:
let rec x y = let x = y in x + x
In essence there is an inner binding that hides the recursive one.
I am writing a function that swaps the contents of two reference calls.
let swap (x : a ref) (y :'a ref) : unit =
where
type 'a ref = {mutable contents : 'a}
I do not know what approach to take in order to solve this. Do I use pattern matching?
This is my test case
let test () : bool =
let r1 = { contents = 5 } in
let r2 = { contents = 6 } in
let _ = swap r1 r2 in
(6, 5) = (r1.contents, r2.contents)
;;
run_test "Swap different" test
Does this work?
let swap x y =
let z = !x in
x := !y;
y := z
Note that := and ! are just normal functions like so:
let (:=) r x = r.contents <- x
let (!) {contents} = contents
If you want to use own your type definition then you can do:
let swap' x y =
let z = x.contents in
x.contents <- y.contents;
y.contents <- z
Finally, if you're using batteries then you can just use BatRef.swap as defined here: http://ocaml-batteries-team.github.com/batteries-included/hdoc2/BatRef.html
fun temp(x) =
let val a = x
in if a mod (x-1) = 0 then x
else temp(x-1)
end;
this is example Standard ML code.
What I want to know is that
for example user call temp(10); then a = 10 and the temp(x-1) is called.
then the variable 'a' will change to 9. Can I keep it as 10 in Standard ML?
If your function contains val a = x, then for any invocation of temp(x), the value of a will be equal to the value of x. If you want to remember the value of a from a previous invocation when you recurse, you need to pass it around as a parameter like this:
fun temp_helper x a =
if a mod (x-1) = 0 then x
else temp_helper (x-1)
fun temp x = temp_helper x x
You could also make the helper function an inner function. If you do that, you can actually remove a as a parameter and instead close over a like this:
fun temp x =
let
val a = x
fun helper x =
if a mod (x-1) = 0 then x
else helper (x-1)
in
helper x
end