I have the following two datatypes:
datatype leaf = Slist of string list | Real of real | nil;
datatype 'a tree = Empty | Node of leaf * 'a tree * 'a tree * 'a tree;
The code below goes through all trees of length one/two and forms a list of the values in the leafs.
fun list12(Empty:'a tree) = nil
| list12(Node(leaf leaf1, 'a tree a1, 'a tree a2, 'a tree a3)) =
if (not(a1 = Empty) andalso not(a2 = Empty) andalso not(a3 = Empty))
then list12(a1)::list12(a2)::list12(a3)
else leaf1::list12(a1)::list12(a2)::list12(a3);
The issue is, I get syntax errors such as
stdIn:94.59-94.66 Error: syntax error: deleting TYVAR ID
stdIn:94.71-94.78 Error: syntax error: deleting TYVAR ID
stdIn:94.83-94.93 Error: syntax error: deleting TYVAR ID ID
stdIn:94.93-94.97 Error: syntax error: deleting RPAREN RPAREN EQUALOP
stdIn:94.98-94.102 Error: syntax error: deleting IF LPAREN
stdIn:94.109-94.116 Error: syntax error: deleting EQUALOP ID
The code in itself isn't complicated. Base case is if it's empty, returns null. If it doesn't have three nodes, then I add the value of the leaf and recursively call the function on the nodes. If it does, I just recursively call the function on the nodes without adding the leaf.
It works because it it's empty, it ends that search by adding nil to the list, which does nothing.
I've also tried other cases such as using and
instead of andalso
, as well as other versions of the code such as
| list12(Node(leaf1, Empty, Empty, Empty)) = nil
| list12(Node(leaf2, a1, Empty, Empty)) = leaf2::list12(a1);
| list12(Node(leaf3, b1, b2, Empty)) = leaf3::list12(b1)::list12(b2);
| list12(Node(leaf4, c1, c2, c3)) = list12(c1)::list12(c2)::list12(c3);
but I've found that the above doesn't match all cases.
Any idea on why the syntax errors are appearing?
Side note, why doesn't 1.0 = 2.0
work, but in the summaries it says it works for reals? It only appears to work for integers, and >
, <
, and so on don't work either.
nil
. It's a reserved keyword for the built-in list type (i.e. nil
= []
).'a tree t1
. You either infer the type (by not specifying it and letting the type-checker guess it), or you annotate it with the proper syntax (t1 : 'a tree
).Assuming we get the syntax errors out of the way, rely a little more on inference by removing the type annotations, and add a little formatting, this is how your code might look like:
datatype leaf = Slist of string list | Real of real | Nil;
datatype 'a tree = Empty | Node of leaf * 'a tree * 'a tree * 'a tree;
fun list12 Empty = []
| list12 (Node(leaf1, a1, a2, a3)) =
if (not(a1 = Empty) andalso not(a2 = Empty) andalso not(a3 = Empty))
then list12(a1)::list12(a2)::list12(a3)
else leaf1::list12(a1)::list12(a2)::list12(a3);
! then list12(a1)::list12(a2)::list12(a3)
! ^^^^^^^^^^
! Type clash: expression of type
! 'a list
! cannot have type
! 'a
! because of circularity
Looking at the type of op:: : 'a * 'a list -> 'a list
, and your use of list12(a1)::list12(a2)
, the type-checker must find some 'a
such that 'a = 'a list
. That is like finding an x
such that x = x + 1
. Clearly, whatever list12
returns, you have something of the same kind on each side.
A dirty and inefficient trick is to use the @
operator (append) instead. A neater way is to fold across the tree in such a way that the function with which you fold has access to the entire node (like in this StackOverflow post from the other day):
fun para f e Empty = e
| para f e0 (t0 as Node (x, t1, t2, t3)) =
let val e1 = f (e0, t0)
val e2 = para f e1 t1
val e3 = para f e2 t2
val e4 = para f e3 t3
in e4 end
fun isNode (Node _) = true
| isNode Empty = false
fun list12 t =
let fun extract (xs, Empty) = xs
| extract (xs, Node (x, t1, t2, t3)) =
if isNode t1 andalso isNode t2 andalso isNode t3
then x::xs
else xs
in para extract [] t end
You could collapse this into just one function - this way is separating the traversal logic into para
and the accumulation logic into list12
's helper function.
real
sWhy doesn't 1.0 = 2.0 work, but in the summaries it says it works for reals?
I don't know what summaries you refer to. This question is answered here: Why can't I compare reals in Standard ML? (this answer was originally placed here, but was moved there, since it's a separate question.)