datatype inttree = Empty | Node of int * inttree * inttree
fun insert(t,i)= if t=Empty then Node(i,Empty,Empty)
else if t=Node(j,l,r):
if (i=j)
then t
else if (i < j)
then Node(j,insert l i,r)
else Node(j,l,insert r i)
the syntax errors are
stdIn:8.7-19.4 Error: syntax error: deleting ELSE ID
stdIn:25.15-25.25 Error: syntax error: deleting FUN ID
stdIn:25.32-25.36 Error: syntax error: deleting IF ID
Oh, the joy of SML error messages.
I'll sidestep your syntax errors (see Gabe's answer) and propose a different solution.
This problem is much more easily (and idiomatically) solved with pattern matching:
fun insert (Empty, i) = Node (i, Empty, Empty)
| insert (Node (j, l, r), i) = <your code here>
(Apologies if the syntax is off, my SML is a bit rusty.)
I left one case for you to fill in, so as not to spoil your fun entirely.
Properly formatted, here's your function:
fun insert(t,i) =
if t = Empty then
Node(i,Empty,Empty)
else if t = Node(j,l,r):
if (i=j) then
t
else if (i < j) then
Node(j,insert l i,r)
else
Node(j,l,insert r i)
Do you see what's wrong? The if t = Node(j,l,r): has no else to match it. Also, it should have a then instead of a colon (:).
Related
I'm trying to select the minimum element in a list based on the third value of its elements. But there seems to be a problem with my usage of higher-order functions in the min_proc function. (I'm using SML in CPN Tools)
fun min_process(p1: DATA, p2: DATA) =
if (#3 p1 <= #3 p2)
then p1
else p2;
fun min_proc(l) =
if (l = [])
then empty
else
if (List.length(l) = 1)
then List.hd(l)
else min_process(List.hd(l), min_proc(List.tl(l)));
Error at:
../compiler/TopLevel/interact/evalloop.sml:66.19-66.27
I'm trying to write a recursive function that works with a record type with a mutable list field.
This function should modify the mutable field during recursive calls, adding new values to the list. Everything worked fine, but when the amount of input data started to increase, I started getting stack overflow errors.
Here is a minimal example that demonstrates my problem:
type ty = { mutable ll : int list; }
let build_list i n =
let rec aux acc i =
if i <= n then
aux (i::acc) (i+1)
else (List.rev acc)
in
aux [] i
let rec mod_rec (acc: int) (a: ty) : (int) =
a.ll <- a.ll # (build_list 0 4000);
let acc = if acc > 0 then mod_rec (acc - 1) a else 0 in
acc
let aty = { ll = [] } in
mod_rec 1000 aty
This leads to the following error:
Stack overflow during evaluation (looping recursion?).
Raised by primitive operation at file "stdlib.ml", line 296, characters 22-31
Called from file "stdlib.ml", line 296, characters 22-31
And I got the same error when using tail recursive functions.
I don't quite understand what is going here. What values does the compiler allocates on the stack? Why it doesn't use a heap to store list elements?
What are the best practices to solve this problem? Should I choice other data structures or use immutable lists with destructive updates?
Thanks for any advices.
I think the problem is that the # operator (equivalent to List.append) is not tail recursive.
The document says this:
Concatenate two lists. Same as the infix operator #. Not tail-recursive (length of the first argument).
You can fix things up by writing a tail-recursive append function.
(* Write a function number_in_month that takes a list
of dates and a month (i.e., an int) and
returns how many dates in the list are in the given month.*)
fun number_in_month(datelist : (int*int*int) list, month : int) =
if null(tl (datelist))
then if #2(hd (datelist)) = month then 1 else 0
else if #2(hd (datelist)) = month
then 1 + number_in_month(tl datelist, month)
else number_in_month(tl datelist, month)
(* Write a function number_in_months that takes a list of dates and a list of months
(i.e., an int list) and returns the number of dates in the list of dates that are
in any of the months in the list of months. Assume the list of months
has no number repeated. Hint: Use your answer to the previous problem. *)
fun number_in_months(datelist : (int*int*int) list, monthlist : int list)
if null(tl (monthlist))
then number_in_month(datelist, hd monthlist)
else number_in_month(datelist, hd monthlist)
+ number_in_months(datelist, tl monthlist)
The second function gives me this error when I try to compile it:
hw1.sml:42.5 Error: syntax error: inserting EQUALOP
[unexpected exception: Compile]
uncaught exception Compile [Compile: "syntax error"]
raised at: ../compiler/Parse/main/smlfile.sml:19.24-19.46
../compiler/TopLevel/interact/evalloop.sml:45.54
../compiler/TopLevel/interact/evalloop.sml:306.20-306.23
../compiler/TopLevel/interact/interact.sml:65.13-65.16
-
"syntax error: inserting EQUALOP" means that SML is expecting a = character.
The error messages from SML/NJ is one of the things that haven't improved one bit over the past twenty years. They often report what the parser does in order to try to recover from an error rather than what the error might be.
List recursion (and most everything else) is much nicer to write with pattern matching than with conditionals and selectors:
fun number_in_month ([], _) = 0
| number_in_month ((_, m, _)::ds, m') = (if m = m' then 1 else 0) + number_in_month(ds, m');
fun number_in_months (_, []) = 0
| number_in_months (ds, m::ms) = number_in_month(ds, m) + number_in_months(ds, ms);
This also lets SML let you know when you have forgotten a case, for instance the case of the empty list (which you forgot about).
Answer: Forgot the = sign. This is correct:
fun number_in_months(datelist : (int*int*int) list, monthlist : int list) =
if null(tl (monthlist))
then number_in_month(datelist, hd monthlist)
else number_in_month(datelist, hd monthlist)
+ number_in_months(datelist, tl monthlist)
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 am learning standard ML and I keep getting this error and I am not sure why?
Here is the code and the error:
> fun in_list(element, list) =
if hd(list) = element then true
else val tempList = List.drop(list, 1);
in_list(element, tempList);
# # Error-Expression expected but val was found
Static Errors
I know there has to be something wrong with the syntax that I am trying.
You need to wrap val values in a let..in..end block.
fun in_list(element, list) =
if hd(list) = element then true
else
let
val tempList = List.drop(list, 1)
in
in_list(element, tempList)
end
Moreover, hd and drop aren't recommended to decompose a list. You should use pattern-matching instead.
fun in_list(element, x::xs) =
if x = element then true
else in_list(element, xs)
There is a base case with empty list missing, and you can use orelseto replace if x = element then true .... I leave them for you as suggestions.