Product of Tree Elements SMLNJ - sml

I have the following qtree datatype:
datatype 'a qtree = Leaf of 'a
| Node of 'a branches
and 'a branches = Empty
| Branch of 'a qtree * 'a branches
An example tree is defined as follows:
val tr1 =
Node(Branch(Leaf(2),
Branch(Node(Branch(Leaf(6),
Branch(Leaf(5),Empty))),
Branch(Node(Empty),Empty))))
Here is a visual representation of tr1:
/|\
/ | \
2 / \
/ \
6 5
I have defined the following function tree_prod to find the product of the values in a qtree:
fun tree_prod(Leaf(n)) = n
| tree_prod(Empty) = 1
| tree_prod(Node(br)) = tree_prod(br)
| tree_prod(Branch(n, br)) = tree_prod(n) * tree_prod(br)
But I am receiving the following errors, which seem to occur due to a type mixup between qtree and branches:
stdIn:10.5-13.42 Error: parameter or result constraints of clauses don't
agree [tycon mismatch]
this clause: 'Z branches -> 'Y
previous clauses: 'X qtree -> 'Y
in declaration:
tree_prod =
(fn Leaf n => n
| Empty => 1
| Node br => tree_prod br
| Branch (<pat>,<pat>) => tree_prod <exp> * tree_prod <exp>)
stdIn:10.5-13.42 Error: parameter or result constraints of clauses don't
agree [tycon mismatch]
this clause: 'Z branches -> 'Y
previous clauses: 'X qtree -> 'Y
in declaration:
tree_prod =
(fn Leaf n => n
| Empty => 1
| Node br => tree_prod br
| Branch (<pat>,<pat>) => tree_prod <exp> * tree_prod <exp>)
stdIn:12.19-12.27 Error: operator and operand don't agree [tycon mismatch]
operator domain: [int ty] qtree
operand: [int ty] branches
in expression:
tree_prod br
stdIn:13.24-13.42 Error: operator and operand don't agree [tycon mismatch]
operator domain: [int ty] qtree
operand: [int ty] branches
in expression:
tree_prod br
How do I fix these errors?
Bonus: How do I implement this function using fold?

Your tree_prod attempts to apply to both types, which won't work - you need two functions.
If it's possible for you to change the type, you can use the fact that 'a branches is isomorphic to a list of 'a qtree (with Empty as nil and Branch as cons).
datatype 'a qtree = Leaf of 'a
| Node of ('a qtree) list
and then you can fold over the branches:
fun tree_prod (Leaf n) = n
| tree_prod (Node br) = List.foldl (fn (tree, acc) => tree_prod tree * acc) 1 br
val tr1 = Node [Leaf 2, Node [Leaf 6, Leaf 5], Node []]
- tree_prod tr1;
val it = 60 : int
If you don't want to change the type, you can write your own fold over 'a branches, following the same form as a list-fold.
Something like this might do it:
fun branch_fold f x Empty = x
| branch_fold f x (Branch t bs) = branch_fold f (f (t, x)) bs
and would give an almost identical "product":
fun tree_prod (Leaf n) = n
| tree_prod (Node br) = branch_fold (fn (tree, acc) => tree_prod tree * acc) 1 br

I have located the answer on my own. By dividing this into two separate functions, I am able to specify which types I am wanting to work with.
Here is the working solution:
fun tree_prod (Leaf(n)) = n
| tree_prod (Node(br)) = branches_prod(br)
and branches_prod (Empty) = 1
| branches_prod (Branch(n, br)) =
tree_prod(n) * branches_prod(br)

Related

SML recursive type error when converting numbers to nat form

I am practicing SML and getting the following recursive type error. Is ML complaining about type recursive and needs some type hints? I am confused.
datatype 'a nat =
Zero
| Succ of 'a
;
fun to_nat(v) = if v = 0 then Zero else Succ(to_nat(v - 1));
fun plus(n1,n2) =
case n1 of
Zero => n2
| Succ(v) => Succ(plus(v, n2))
;
fun multiply(n1,n2) =
case n1 of
Zero => Zero
| Succ(v) => plus(multiply(v, n2), n2)
;
val five = to_nat(5);
val six = to_nat(6);
val eleven = plus(five, six);
val thirty = multiply(five, six);
Error:
Standard ML of New Jersey v110.79 [built: Sat Oct 26 12:27:04 2019]
[opening lambda.sml]
datatype 'a num = Succ of 'a | Zero
lambda.sml:6.5-6.60 Error: right-hand-side of clause doesn't agree with function result type [circularity]
expression: 'Z num
result type: 'Z
in declaration:
to_num = (fn v => if <exp> = <exp> then Zero else Succ <exp>)
/usr/lib/smlnj/bin/sml: Fatal error -- Uncaught exception Error with 0
raised at ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27
I believe you made a mistake in defining your data type. You want Succ to take a value of type 'a nat rather than 'a.
datatype 'a nat = Zero | Succ of 'a nat;
The 'a parameter makes no sense, and is probably what lead you down the wrong path.
(For instance, Succ "hello" or Succ ([1], true, "world") seem very odd constructs of natural numbers.)
You want just
datatype nat =
Zero
| Succ of nat

operator and operand do not agree [tycon mismatch]

I am trying to write a function in sml that takes in a list of pairs and returns pair of two list of all the elements
Meaning if the input is [(1, 2.0), (2, 3.0)]
The output should be ([1, 2], (2.0, 3.0))
fun divide nil = (nil , nil)
| divide [(a, b)::nil] = ([a], [b])
| divide [(a, b)::myTl] =
let
val (x, y) = divide myTl
in
(a::x, b::y)
end
;
Never the less the sml interpreter returns the following err
Error: operator and operand do not agree [tycon mismatch]
operator domain: ('Z * 'Y) list list
operand: ('Z * 'Y) list
in expression:
divide myTl
The error message you're seeing is because you've (inadvertently) declared a function with domain ('a * 'b) list list due to your input patterns, so your recursive call is not well typed.
The most straightforward fix is to correct for the incorrect use of [ ] around the argument to the function---this is making a singleton list, instead of just grouping the pattern. Thus you'd want to use ( ) instead.
fun divide nil = (nil , nil)
| divide ((a, b)::nil) = ([a], [b])
| divide ((a, b)::myTl) =
let
val (x, y) = divide myTl
in
(a::x, b::y)
end
Your second base case is also extraneous, so we could further revise this to
fun divide [] = ([], [])
| divide ((a, b)::xs) =
let
val (x, y) = divide xs
in
(a::x, b::y)
end

Issue with a tycon mismatch

Working on a homework assignment that essentially takes a tree, the declaration of which is:
datatype a BinTree =
Leaf of a
| Node of a BinTree * a BinTree;
and returns a tuple of an int height of tree and a list of values which were stored at that deepest portion of the tree.
fun deepest tree =
case tree of
Leaf(n) => [n]
| Node(l, r) => if #1(deepest l) > #1(deepest r) then ((#1(deepest l) + 1), #2(deepest l)) else
if #1(deepest l) < #1(deepest r) then ((#1(deepest r) + 1), #2(deepest r)) else
(1, #2(deepest l) # #2(deepest r));
Trying to test this code, I come up with the following error message:
stdIn:43.1-47.35 Error: types of rules don't agree [tycon mismatch]
earlier rule(s): 'Z BinTree -> 'Z list
this rule: 'Z BinTree -> [+ ty] * 'Y list
in rule:
Node (l,r) =>
if (fn <rule>) (deepest <exp>) > (fn <rule>) (deepest <exp>)
then (<exp> <exp> + 1,(fn <rule>) (deepest <exp>))
else if <exp> <exp> < <exp> <exp>
then (<exp> + <exp>,<exp> <exp>)
else (1,<exp> # <exp>)
stdIn:21.2-47.35 Error: right-hand-side of clause doesn't agree with
function result type [type mismatch]
expression: 'Z list
result type: {1:[+ ty], 2:'X list; 'Y}
in declaration:
deepest =
(fn tree =>
(case tree
of <pat> => <exp>
| <pat> => <exp>))
stdIn:1.2-47.35 Error: unresolved flex record (need to know the names of ALL
the fields
in this context)
type: {1:[+ ty], 2:'Y list; 'Z}
While I do understand that its a type conflict, I can't find what the conflict is, nor how to fix it. Any help would be appreciated.
This
earlier rule(s): 'Z BinTree -> 'Z list
comes from the leaf case ([n]), which makes it a function from trees to lists.
And this:
this rule: 'Z BinTree -> [+ ty] * 'Y list
comes from the node case, making it a function from trees to pairs of "a type that supports addition" and lists.
The remaining errors are caused by SML not being able to deduce what #1 and #2 mean in the presence of that conflict.
Your base case is wrong – it should be a pair, not a list.
The depth in that pair should be 1, and the depth should not be 1 in the case where both subtrees are equally deep.
You're also computing the deepest values three times for each subtree in the worst case, and two in the best case.
It's better to recurse only once for each subtree.
Something like this:
fun deepest (Leaf n) = (1, [n])
| deepest (Node (l, r)) =
case deepest l of (dl, ll) =>
case deepest r of (dr, lr) =>
if dl > dr then (dl + 1, ll)
else if dr > dl then (dr + 1, lr)
else (dl + 1, ll # lr)
While I also prefer case-of like molbdnilo for writing this function, here is an example of using let-in-end to demonstrate that they can both be used when the result is a product (tuple). Since there are three cases in the if-then-else with three distinct outcomes (dl > dr, dr > dl and dl = dr), using Int-compare may be preferable:
fun deepest (Leaf n) = (1, [n])
| deepest (Node (l, r)) =
let val (lcount, ls) = deepest l
val (rcount, rs) = deepest r
in case Int.compare (lcount, rcount) of
GT => (lcount + 1, ls)
| LT => (rcount + 1, rs)
| EQ => (lcount + 1, ls # rs)
end

Quicksort in SML operator and operand don't agree error

I am trying to write a quicksort function of type
'a list * ('a * 'a -> bool) -> 'a list
but for some reason I am getting:
'a list -> ('a * 'a -> bool) -> 'a list
Here is my code for the function:
fun quicksort xs f = let
fun qs [] = []
| qs [x] = [x]
| qs (p::xs) = let
val (less, more) = List.partition (fn x => f (x, p)) xs
in
qs less # p :: qs more
end
in
qs xs
end
When I call the function I get this error:
stdIn:73.1-73.18 Error: operator and operand don't agree [tycon mismatch]
operator domain: 'Z list
operand: int list * (int * int -> bool)
in expression:
quicksort (L, op <)
I realize that I must be passing it in wrong, but I just can't see my mistake. So, my question is what is going on here in which I get this error while trying to pass in my list and operator?
You could simple change:
fun quicksort xs f = let
to:
fun quicksort (xs,f) = let
since you want quicksort to have as parameters a tuple (xs,f).

ML. How to correctly work with sequences

So I have this "new" two way sequence:
datatype direction = Back | Forward;
datatype 'a bseq = bNil
| bCons of 'a * (direction -> 'a bseq);
and I need a function seq2bseq : 'a seq -> 'a seq -> 'a bseq that "appends" two regular sequences into one like so:
if seqUp is 0 1 2 3 4 ... and seqDown is -1 -2 -3 -4 ... then seq2bseq will create .. -4 -3 -2 -1 0 1 2 3 4 .. . In other words the starter element is the first of seqUp(0) so if I move Back I will get to the first element of seqDown(-1) and two the second of the seqUp(1) if I move Forward.
So far I wrote the following:
fun appendq (Nil, yq) = yq
| appendq (Cons(x,xf), yq) = Cons(x,fn()=>appendq(xf(),yq));
fun seq2bseq (DownSeq) (UpSeq) =
bCons(head(UpSeq), fn (Forward) => seq2bseq appendq(head(UpSeq), DownSeq) tail(UpSeq)
| (Back) => seq2bseq tail(DownSeq) appendq(head(DownSeq), UpSeq) );
for which I get the following errors:
stdIn:28.101-28.153 Error: operator and operand don't agree [tycon mismatch]
operator domain: 'Z seq * 'Z seq -> 'Z seq
operand: 'Y seq -> 'Y seq
in expression:
seq2bseq tail
stdIn:27.5-28.155 Error: right-hand-side of clause doesn't agree with function result type [tycon mismatch]
expression: _ seq -> _ bseq
result type: _ * _ -> ('Z seq -> 'Z seq) -> _ seq -> _
in declaration:
seq2bseq = (fn arg => (fn <pat> => <exp>))
I can't figure out what's wrong(:/). Help!
Thanks!
Edit: working(?) code at: http://www.beetxt.com/mkX/.
Your type errors appear to be coming from a lack of parenthesization.
If you have functions foo and bar, and want to call foo on the result of calling bar on the value baz, then you need to write this as foo (bar baz) or foo (bar (baz)), if you prefer.
Writing foo bar(baz) will cause foo to be called with the argument bar, which will likely not type-check.
Try:
fun seq2bseq (DownSeq) (UpSeq) =
bCons(head(UpSeq),
fn Forward => seq2bseq (appendq(head(UpSeq), DownSeq)) (tail(UpSeq))
| Back => seq2bseq (tail(DownSeq)) (appendq(head(DownSeq), UpSeq))
)