The following function is using pattern matching.
fun f (x,0) = x
| f (0,y) = y
| f (x,y) = x+y;
I want to write this using if-else. This function of mine works fine:
fun f1(x, y) =
if y = 0 then x
else if x = 0 then y
else x + y;
But I want to use #0 and #1 destructors (as an assignment). The following function
fun f2(arg) =
if #0(arg) = 0 then #1(arg)
else if #1(arg) = 0 then #0(arg)
else #0(arg) + #1(arg);
gives the following error:
Error: syntax error: deleting INT0 LPAREN
I have no idea what the error means and how to fix it.
There's two issues I can identify with your snippet.
SML tuples are 1-indexed, so it'd be #1 to extract the first component, not #0.
SML won't be able to infer the record's type correctly just from those usages, so you should annotate it explicitly: fun f2 (arg : int * int) = ....
So, with a little modification:
fun f2 (arg : int * int) =
if #1 arg = 0 then #2 arg
else if #2 arg = 0 then #1 arg
else #1 arg + #2 arg
works fine for me (compiled using MLton).
In terms of style and semantics, the match version is far preferable.
If you're going to go with the manual decision tree (which isn't the same sequence of tests as the pattern matching version would produce), you could at least hoist out the common access expressions:
let
val x = #1 arg
val y = #2 arg
in
...
end
Related
I want to calculate f(..f(x)) p times. The following is my code.
let rec function f x p = if p = 0 then x else function f (f x) p-1;;
I wonder how I should make it right.
This is very close, but your code has syntax errors that are going to make it hard to make progress. I think the main problem is that you're using function as an identifier, but it is a keyword in OCaml. If you change to myfun, things should start working quite a bit better.
You also need to watch your precedences. The following code:
f a b-1
is parsed like this:
(f a b) - 1
not like this:
f a (b - 1)
You need to write the parentheses explicitly to get this second parse.
You can define a recursive function ch to apply a function f many times (Church numeral??) as follows:
let rec ch f p x = if p = 0 then x else f (ch f (p-1) x);;
The problems in your original code are that:
need to name the function as something, such as ch here.
need to call the same function ch to get the recursion going as shown above. In your original code, there is no recursion.
Example
let p1 x = x + 1 ;;
ch p1 3 1 ;;
this will give you
- : int = 3
as intended.
I wrote a function that is supposed to receive a list of tuples. I access the components of the tuples with # and the code compiles:
fun recheck ([], n) = []
| recheck (h::t, n) =
if ((#1 h) * (#1 h)) + ((#2 h) * (#2 h)) = n then
h::recheck(t, n)
else
recheck(t, n)
But another function that basically does the same thing, namely receiving a list of tuples and accessing those, causes an error.
fun validate ([]) = true
| validate (h::t) =
if 1 = (#1 h) then
true
else
false
Can't find a fixed record type. Found near #1
What is the difference here and why does the latter cause an error?
Edit
The first function actually does not compile on its own.
But this entire snippet does:
fun drop ([], n) = []
| drop (h::t, 0) = h::t
| drop (h::t, n) =
drop(t, n-1)
fun sts_linear (y, n) =
if y < (Math.sqrt(n)+1.0) then
let
(* x^2 + y^2 = n => x = sqrt(n-y^2) *)
val x = Math.sqrt(n - (y * y));
val xr = Real.realRound(x);
in
if (abs(x - xr) < 0.000000001) then
[(Real.trunc xr, Real.trunc y)]#sts_linear (y+1.0, n)
else
(
[]#sts_linear (y+1.0, n)
)
end
else []
fun recheck ([], n) = []
| recheck (h::t, n) =
if ((#1 h) * (#1 h)) + ((#2 h) * (#2 h)) = n then
h::recheck(t, n)
else
recheck(t, n)
fun sts (n) =
(
let
val pairs = sts_linear(0.0, Real.fromInt n);
in
recheck(drop(pairs, Real.ceil( Real.fromInt (length(pairs))/2.0 ) ), n)
end
)
Your first code doesn't compile, at least with SML/NJ:
If you got it to compile then it must have been in a nonstandard extension of SML.
The problem with both of your definitions is that there is no polymorphic idea of a tuple of arbitrary arity in SML. You can write functions to work on lists of pairs. You can write functions to work on lists of triples. But -- you can't write functions to work simultaneously on lists of pairs and lists of triples (at least if your function tries to do things with these pairs/triples as tuples).
One solution is to get rid of # and use pattern-matching to extract the components:
fun validate [] = true
| validate ((x,y)::t) =
if x = 1 then
true
else
false
But, if you really want to write a function which can polymorphically apply to either lists of pairs or list of triples (or quadruples,...), the easiest thing to do is to represent the pairs, triples, etc. as lists rather than tuples. Lists which contains lists of nonspecified size are not a problem in SML.
Trying to minimize this down, as I have seen the following work in SML/NJ
and i'm not aware of it actually being a compiler extension
val p1 = {x=0, y=0};
val p2 = {x=1, y=1};
val p3 = {x=1, y=1, z=1};
There is an awkward construct from a compiler error perspective
not many languages have errors that work in this fashion,
because the function is valid, but produces a type error
unless an invocation of the function exists to resolve the
type of 'record', thus to resolve the error more code must be added.
fun getFoo(field) = fn record => field record;
Without the following actual calling of the getX
the compiler cannot determine the type of record
of which the complete type information of ALL fields
of the record must be known to the compiler, not just the #x field.
let val getX = getFoo(#x);
val x1 = getX(p1);
val x2 = getX(p2);
val x3 = getFoo(#x)(p3);
in () end;
while the following commented out snippet results in an error because the types of
p1 and p3 are different, and so different invocations of getFoo
are required
(*
let val getX = getFoo(#x);
val x1 = getX(p1);
val x3 = getX(p3);
in () end;
*)
and the following is insufficient since it never resolves the record.
let val getX = getFoo(#x) in () end;
I want to find the first occurence of a digit in a list :
let pos_list = function (list , x) ->
let rec pos = function
|([] , x , i) -> i
|([y] , x , i) -> if y == x then i
|(s::t , x , i) -> if s == x then i else pos(t , x , i + 1) in pos(list , x , 0) ;;
but the compiler complain that the expression is a "uint" type , and was used instead with a "int" type .
Remove the second case from the pattern matching. This case is already matched by the last one with s = y, t = []. So the function can be simplified to
let pos_list (list, x) =
let rec pos = function
| ([], x, i) -> i
| (s::t, x, i) -> if s == x then i else pos(t, x, i + 1) in pos(list, x, 0) ;;
Why are you using == (physical equality) instead = which is structural equality? I realize that this might not make a difference if you only have integers but it might yield unexpected behaviour down the road.
See the Comparisons section in the doc: http://caml.inria.fr/pub/docs/manual-ocaml/libref/Pervasives.html
Pavel Zaichenkov's answer is of course the best one, but you might be interested in knowing the exact cause of the error. Namely, when you have
if y == x then i
without a corresponding else expression, the whole expression is treated as
if y == x then i else ()
where () is the only value of the type unit (and not uint), which is the type of expressions that are evaluated for their side effects only. Since both branches of the if must have the same type, i is deemed to have type unit also. Then, when type-checking the third branch of the pattern-matching, you try to add i and 1, which means that i should have type int, hence the type error.
I have following piece of code:
let p = print_string("finished\n");;
let x0 = ref 0;;
class point =
object
val mutable x = incr x0; !x0
method get_x = x
method move d = x <- x + d
end
;;
print_int(new point#get_x);;
p;;
print_int(new point#get_x);;
p;;
Can't understand why the output is:
finished
12
My expectation is actually like:
1
finished
2
finished
Anyone can tell what's the correct order of executing this piece of code?
The main point of confusion is that your p isn't a function. It's just a value. In particular, it is the value () (known as unit). So when you evaluate p later in your code it has no effect. All the work was done when p was created.
If you want p to act like a function (which is what you seem to want), you should define it like this:
let p () = print_string "finished\n";;
And you should call it like this:
p ();;
I want to write something like
fun factorial 0 = 1
| factorial n = n * factorial(n-1);
but I don't get the "|" sign when i want to start the new line. I get something like:
fun factorial 0 = 1
= factorial n = n * factorial(n-1);
when I start the second line of code. If I hold shift and "\" I dont get the vertical bar, I get something else.
Since you say that the second line starts with an equal sign (=), it appear that you are writing your code directly into the interpreter?
In any case you have to write the pipe your self. The pipe is part of the SML syntax, and is used to "indicate" different function clauses, whereas the semicolon has a double meaning here. Doubling as being part of the SML syntax (though not strictly needed here) and as a special indicator to the interpreter (as explained below).
Most interpreters will keep reading data from stdin until it reads a semicolon, and first then will it start to interpret what you have written.
In the case of the SML/NJ interpreter, the first line is indicated by starting with a "-" and any subsequent lines starts with a "=". Note that the "-" and "=" signs are not interpreted as part of the final program.
An example of this can be seen below
- fun foo 0 y = 0
= | foo 1 y = y
= | foo x y = x*y;
val foo = fn : int -> int -> int
Here the last line is the output from the interpreter, when it reads the semicolon.
However we could also have declared two functions before writing the semicolon
- fun foo 0 y = 0
= | foo 1 y = y
= | foo x y = x * y
= fun fact 0 = 1
= | fact n = n * fact (n-1);
val foo = fn : int -> int -> int
val fact = fn : int -> int
Regarding the pipe, it depends on your keyboard layout, whether or not you will get it by typing shift+"\". However since your post contains multiple pipes, I suppose you already know how to write one.