Let's say I have a tuple:
let x = (1,3)
I want to add 1 to only the first value of the tuple. How would I do that?
You use pattern matching to deconstruct the tuple and then construct the updated one:
let (x1, x2) = x in (x1 + 1, x2)
Patterm matching is a typical idiom. Another way would be with fst and snd:
# let x = (1,3);;
val x : int * int = (1, 3)
# let y = (fst x + 1, snd x);;
val y : int * int = (2, 3)
Related
In imperative languages I can easily write something like this:
if(x > y) {
int t = x;
x = y;
y = t;
}
The values of the variables are getting passed to another. However if I try writing this in Ocaml, the compiler sees this as a comparison, so it turns out to be bool:
if x > y then
let t = x in
let x = y in
let y = b in
How can I pass the value of variables to another?
Rather than variables, OCaml has named values. If you want to shuffle the names of some values, you can write:
let x, y =
if x > y then y, x
else x, y
in
If you want to mirror the imperative code exactly you would write:
# let x = ref 2;;
val x : int ref = {contents = 2}
# let y = ref 1;;
val y : int ref = {contents = 1}
# let swap_if x y = if !x > !y then let t = !x in x := !y; y := t;;
val swap_if : 'a ref -> 'a ref -> unit = <fun>
# swap_if x y;;
- : unit = ()
# !x, !y;;
- : int * int = (1, 2)
Writing it functional you would do
let (x, y) = if x > y then (y, x) else (x, y)
or
let (x, y) = (min x y, max x y)
But note that this will not change x and y. Rather it creates new variables x and y that shadow the previous bindings.
Newbie at SML
I have the following code that returns the absolute value of a list. I need it to be of type int list -> real list. Where do I place the statement that converts it to real while constraining this code to a single line?
val myabs = map(fn x => if x >= 0 then x else ~x) [1,~2, 3, ~4];
You convert an int to real using Real.fromInt:
- Real.fromInt 42;
> val it = 42.0 : real
You can convert an int list into a real list by List.map Real.fromInt:
- List.map Real.fromInt [1, 2, 3];
> val it = [1.0, 2.0, 3.0] : real list
You can convert an integer to its absolute using Int.abs:
- Int.abs ~42;
> val it = 42 : int
You can combine those two functions and so both convert an integer to its absolute and convert it to real:
- (Real.fromInt o Int.abs) ~42;
> val it = 42.0 : real
And you can do this for an entire list using List.map (Real.fromInt o Int.abs):
- List.map (Real.fromInt o Int.abs) [~1, ~2, ~3];
> val it = [1.0, 2.0, 3.0] : real list
You can express that as a single function:
fun myabs xs = List.map (fn x => Real.fromInt (Int.abs x)) xs
And you can shorten this function a bit:
val myabs = List.map (fn x => Real.fromInt (Int.abs x))
val myabs = List.map (fn x => (Real.fromInt o Int.abs) x)
val myabs = List.map (Real.fromInt o Int.abs)
So the only missing pieces were:
Instead of if x >= 0 then x else ~x, use Int.abs x.
To convert x to real, use Real.fromInt x.
To apply multiple functions in sequence, f (g x) or (f o g) x, like math.
So I came across with the op operator and I don't get the pupurse.
I defined two functions:
fun op pow1 (x,y) = Math.pow (x,y);
fun pow2 (x,y) = Math.pow (x,y);
They both have the same signatures:
val pow1 = fn : real * real -> real
val pow2 = fn : real * real -> real
And they both have the same function calls:
pow1 (5.0,6.0);
> val it = 15625.0 : real
pow2 (5.0,6.0);
> val it = 15625.0 : real
So what is the difference between those two functions? What is the idea behind op?
The op keyword undoes the infix status of the following (alphanumerical or symbolic) identifier. For example:
val n = op+ (1, 2) (* equivalent to: val n = 1 + 2 *)
val m = op mod (5, 6) (* equivalent to: val m = 5 mod 6 *)
fun op+ (x, y) = x - y (* equivalent to: fun x + y = x - y *)
These lines would be syntax errors otherwise.
This is useful when referring to a normally-infix function without immediately invoking it, such as when passing it to a higher-order function. For example:
List.foldr op+ 0 [1, 2, 3] (* equivalent to: 1 + (2 + (3 + 0)) *)
I'm currently studying SML and I'm having a hard time understanding the code below
fun good_max (xs : int list) =
if null xs
then 0
else if null (tl xs)
then hd xs
else
(* for style, could also use a let-binding for (hd xs) *)
let val tl_ans = good_max(tl xs)
in
if hd xs > tl_ans
then hd xs
else tl_ans
end
hd xs is of type int and tl_ans, I think is of type list.
Why does this code work? How does the system evaluate the recursion?
It would be great if you could use xs = [3, 4, 5] to show me how this works.
Let me first rewrite this code to an equivalent but more readable version:
fun max(x,y) = if x > y then x else y
fun goodMax(nil) = 0
| goodMax(x::nil) = x
| goodMax(x::xs) = let val y = goodMax(xs) in max(x,y) end
Now we can consider how evaluation of goodMax([3,4,5]) proceeds: conceptually, it will be reduced to an answer by repeatedly substituting the respective branch of the function definition(s):
goodMax([3,4,5])
= goodMax(3::[4,5])
= let val y = goodMax([4,5]) in max(3, y) end
= let val y = goodMax(4::[5]) in max(3, y) end
= let val y = (let val y' = goodMax([5]) in max(4, y') end) in max(3, y) end
= let val y = (let val y' = goodMax(5::nil) in max(4, y') end) in max(3, y) end
= let val y = (let val y' = 5 in max(4, y') end) in max(3, y) end
= let val y = max(4, 5) in max(3, y) end
= let val y = (if 4 > 5 then 4 else 5) in max(3, y) end
= let val y = 5 in max(3, y) end
= max(3, 5)
= if 3 > 5 then 3 else 5
= 5
I have renamed the y in the inner invocation to y' for clarity.
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);