In sml, why it produce Error: syntax error: deleting IN IF - emacs

I'm making a function to determine whether a tree is balanced or not.
fun balanced(tree) =
let
fun size tree =
case tree of
Lf => 0
| Br(xs,ys,zs) => 1 + size ys + size zs
fun depth tree =
case tree of
Lf => 0
| Br(xs,ys,zs) =>
let val l_count = 1 + depth ys
val r_count = 1+ depth zs
in
if l_count > r_count then l_count else r_count
end
in
if size(ys) = size(zs) andalso depth(ys) = depth(zs) then true
else if tree=Lf then true
else false
end;
But it produces these errors:
stdIn:829.18-829.20 Error: unbound variable or constructor: zs
stdIn:829.9-829.11 Error: unbound variable or constructor: ys
stdIn:829.48-829.50 Error: unbound variable or constructor: zs
stdIn:829.36-829.38 Error: unbound variable or constructor: ys

Between in and end
in
if size(ys) = size(zs) andalso depth(ys) = depth(zs) then true
else if tree=Lf then true
else false
end;
you use ys and zs that you never define before. The ys and zs you have in depth and size functions are local to these functions and not visible to balanced.

You have not provided the datatype that this function operates on. I assume it looks like this:
datatype 'a binary_tree = Lf | Br of 'a * 'a binary_tree * 'a binary_tree
You get the unbound variable errors because the code
if size(ys) = size(zs) andalso ...
does not have such variables in its scope. Those variables are only available in the scope of your helper functions. Here's some hints:
Don't name your variables xs, ys and zs when xs is in fact the value residing in the branch and ys and zs are in fact the left and right sub-trees of the branch. Better names could be x (or _ if you don't use it), left and right.
Use Int.max (x, y) instead of if x > y then x else y.
Similarly, if foo then true else false is equivalent to just foo.
So you don't need if-then-else in the body of balanced.
Perform the pattern match directly in the function argument.
It isn't necessary to know the number of elements in a sub-tree (size) to determine if it's balanced. It's only necessary to know the tree's height/depth (depth).
Move the helper functions out of this function.
They're useful in their own right.
fun size Lf = 0
| size (Br (_, left, right)) = 1 + size left + size right
fun depth Lf = 0
| depth (Br (_, left, right)) = 1 + Int.max (depth left, depth right)
Write balanced in a declarative way: An empty tree (Lf) is trivially balanced. A non-empty tree (Br ...) is balanced if the left sub-tree is balanced, the right sub-tree is balanced, and the difference of the depth of the left and the right sub-tree is not more than 1.
fun balanced Lf = true
| balanced (Br (_, left, right)) =
balanced left andalso
balanced right andalso
...the 'abs'(olute) difference of 'depth left' and 'depth right' is not more than 1...
This solution traverses the tree quite a lot: First with balanced and then with depth. You can write a solution to this exercise that only traverses the tree once by returning a tuple (is_subtree_balanced, subtree_height).
fun balanced_helper Lf = (true, 0)
| balanced_helper (Br (_, left, right)) =
let val (is_left_balanced, left_height) = balanced_helper left
in ...we can stop here if the left sub-tree isn't balanced...
let val (is_right_balanced, right_height) = balanced_helper right
in ...we can stop here if the right sub-tree isn't balanced...
...otherwise: (true, 1 + Int.max(left_height, right_height))...
end
end
fun balanced tree = #1 (balanced_helper tree)

Related

How to check if a value exists in a list in smlnj

I'm working on some homework and I need to create a function that checks if a value exists in a list. If it does it will return true, otherwise it returns false. I have an idea of how to do it but I keep getting errors. I think it may be due to my lack of knowledge of syntax and style as this is my first time coding in sml.
I created the function exist and am passing a value and list in as a tuple.
fun exist (x, []) =
if x = hd ([]) then true
else if x = tl ([]) then true
else false;
Sorry if this code is laughably incorrect but I get the error message:
" stdIn:2.6 Warning: calling polyEqual
stdIn:3.11 Warning: calling polyEqual
stdIn:1.6-4.11 Warning: match nonexhaustive
(x,nil) => ...
val exist = fn : ''a list * 'b list -> bool "
and I'm not really sure how to fix this. Any help would be great.
Your function is pattern-matching on [], so it can only ever match the empty list.
Also, hd [] and tl [] are both errors since the empty list has neither head nor tail.
Further, if some_condition then true else false is equivalent to some_condition.
(And if some_condition then false else true is equivalent to not some_condition.)
Logical expressions are usually more readable than chains of conditionals.
And you forgot to recurse; you need to use exist on the tail of the list if the first element is not what you're looking for.
Either stick to pattern matching:
fun exist (_, []) = false
| exist (x, y::ys) = x = y orelse exist (x, ys)
or don't use it:
fun exist (x, xs) = not (null xs) andalso (x = hd xs orelse exist (x, tl xs))
Pattern matching is often the most readable solution and gives a clear picture of the various cases.
(You seem to have mixed the two forms, treating [] as an identifier rather than a type constructor.)

quicksort in ML

Without using case expressions (that comes in the next section of the class), I can't see why the following doesn't do a quicksort. It goes into a loop somewhere and never ends.
splitAt and append have already been thorughly tested, but here are the codes for them.
fun append(xs, ys) =
if null xs
then ys
else (hd xs) :: append(tl xs, ys)
fun splitAt(xs : int list, x : int) =
let
fun sp(ys : int list, more : int list, less : int list) =
if null ys
then (more, less)
else
if hd ys < x
then sp(tl ys, more, append(less, [hd ys]))
else sp(tl ys, append(more, [hd ys]), less)
in
sp(xs, [], [])
end
fun qsort(xs : int list) =
if length xs <= 1
then xs
else
let
val s = splitAt(xs, hd xs)
in
qsort(append(#2 s, #1 s))
end
And I get the same problem using append(qsort(#2 s), qsort(#1 s)), but I though the former was better style since it only require a single recursion with each round.
I guess I should say that 'splitAt' divides the list into greater than or equal to the second argument, and less than, and creates a tuple). Append concatenates 2 lists.
PS: This is only a practice problem, not a test or homework.
It goes into a loop somewhere and never ends.
Your problem is most likely qsort being called on a list that does not reduce in size upon recursive call. Perhaps go with append(qsort (#2 s), qsort (#1 s)). But even then, can you be sure that each of #1 s and #2 s will always reduce in size?
Ideally you should supply splitAt and append since they're not library functions. You might consider using the built-in append called # and the built-in List.partition to form splitAt.
Compare against this one found somewhere on the interwebs:
fun quicksort [] = []
| quicksort (x::xs) =
let
val (left, right) = List.partition (fn y => y < x) xs
in
quicksort left # [x] # quicksort right
end
Since this isn't homework ...
Note that if xs = [1,2] then splitAt(xs hd xs) returns ([1,2],[]) so the attempt to sort [1,2] by this version of qsort reduces to ... sorting [1,2] again. That will never terminate.
Instead, I would advocate applying splitAt to the tail of the xs. A minimal tweak to your code is to leave append and splitAt alone but to rewrite qsort as:
fun qsort(xs : int list) =
if length xs <= 1
then xs
else
let
val s = splitAt(tl xs, hd xs)
in
append(qsort(#2 s), (hd xs) :: qsort(#1 s))
end;
Then, for example,
- qsort [4,2,1,2,3,6,4,7];
val it = [1,2,2,3,4,4,6,7] : int list
It is crucial that you apply qsort twice then append the results. Tryng to apply qsort once to the appended split would be trying to reduce qsort to applying qsort to a list which is the same size as the original list.
SML really becomes fun when you get to pattern matching. You should enjoy the next chapter.

Scala code analyzer targets case variable names that are identical to the outer matched varables - "suspicous shadowing"

In the following code snippet in which the outer match vars (x,y) are case matched by (xx,yy):
scala> val (x,y) = (1,2)
x: Int = 1
y: Int = 2
scala> (x,y) match {
| case (xx:Int, yy:Int) => println(s"x=$x xx=$xx")
| }
x=1 xx=1
We could have also written that code as follows:
scala> (x,y) match {
| case (x:Int, y:Int) => println(s"x=$x y=$y")
| }
x=1 y=2
In this latter case the Scala Code Analyzers will inform us:
Suspicious shadowing by a Variable Pattern
OK. But is there any situation where we could end up actually misusing the inner variable (x or y) in place of the original outer match variables?
It seems this is purely stylistic? No actual possibility for bugs? If so i would be interested to learn what the bugs could be.
This could be confusing:
val x = Some(1)
val y = Some(2)
(x, y) match {
case (Some(x), Some(y)) => println(s"x=$x y=$y")
}
x and y have different types depending on whether you are inside or outside of the match. If this code wasn't using simply Option, and was several lines longer, it could be rather difficult to reason about.
Could any bugs arise from this? None that I can think of that aren't horribly contrived. You could for example, mistake one for another.
val list = List(1,2,3)
list match {
case x :: y :: list => list // List(3) and not List(1,2,3)
case x :: list => list // List with 1 element, should the outer list have size 2
case _ => list // Returns the outer list when empty
}
Not to mention what a horrible mess that is. Within the match, list sometimes refers to an inner symbol, and sometimes the outer list.
It's just code that's unnecessarily complicated to read and understand, there are no special bugs that could happen.

Working With Units in ML (SML/NJ)

I am trying to make a function that will print binary trees. My binary tree datatype looks like this:
datatype 'a BT = empty | bTree of 'a * 'a BT * 'a BT;
I have also made a function that prints integers, which I will be using for the nodes:
fun printInt n = print (Int.toString n);
As you can see, the BT datatype has 3 nodes ('a,'a BT, 'a BT), I have started making a displayTree function, but cannot find a way to print out the unit types that my printInt function returns. I'm sure that there are other ways to do this, but in this case, how would I return three concatenated unit types. Here is what I have so far (I understand that the #s are incorrect).
fun displayTree T =
let
val bTree (root, left, right) = T;
in
(printInt root)# (displayTree left) # (displayTree right)
end;
I am not worried about the line formatting of the trees yet. I am just unsure of how to append my (printInt root) to the recursive calls.
EDIT:
I want the displayTree function to be polymorphic
There are several problems with your code so it's difficult to know where to start. If you want printInt to actually print the value of the node and return unit then you don't want to do anything with the result. You should simply discard it and the calls should look like
(printInt root; displayTree left; displayTree right)
You may not need the parentheses inside the let..in..end block but you need the semicolons.
Other problems are that you need to pattern match on the tree. Also by including printInt in the body of displayTree you are only able to print values of type int bTree. If you want displayTree to be polymorphic you need to pass in a function to print the node since it will depend on the type of the node. The function you pass in could be printInt if the node is an integer but something else for a node of a different type.
You have to make few changes in order to get this code working:
Change tree definition to:
datatype btree =
Empty |
Node of int * btree * btree;
printInt function is to short, so I will avoid it in this case:
fun displayTree T =
case T of
Empty => ""
|Node(root, left, right) => (Int.toString root) ^ (displayTree left) ^ (displayTree right)
Note that this function returns string that represents tree, so you can print it when needed. String concatenation is represented by #. And the secret ingredient that you was missing in your function is called "pattern matching". In this case you can avoid pattern matching with if statement.
Let's make a polymorphic type first:
datatype 'a btree =
Empty |
Node of 'a * 'a btree * 'a btree
Let's make this function polymorphic:
fun displayTree T f =
case T of
Empty => ""
|Node(root, left, right) => (f root) ^ (displayTree left f ) ^ (displayTree right f )
Now you have to define function f that converts your anonymous type to a string.
Let's go a step further and define same function that returns a list of node values that you can print:
fun displayTree T f =
case T of
Empty => [""]
|Node(root, left, right) => [f root] # (displayTree left f) # (displayTree right f)
And you can turn this to return list a of units:
fun displayTree T f =
case T of
Empty => [print ""]
|Node(root, left, right) => [print(f root)] # displayTree left f # displayTree right f
but I don't understand what are you going to do with them.

Explain some scala code - beginner

I've encountered this scala code and I'm trying to work out what its doing except the fact it returns an int. I'm unsure of these three lines :
l match {
case h :: t =>
case _ => 0
Function :
def iterate(l: List[Int]): Int =
l match {
case h :: t =>
if (h > n) 0
case _ => 0
}
First, you define a function called iterate and you specified the return type as Int. It has arity 1, parameter l of type List[Int].
The List type is prominent throughout functional programming, and it's main characteristics being that it has efficient prepend and that it is easy to decompose any List into a head and tail. The head would be the first element of the list (if non-empty) and the tail would be the rest of the List(which itself is a List) - this becomes useful for recursive functions that operate on List.
The match is called pattern matching.. it's essentially a switch statement in the C-ish languages, but much more powerful - the switch restricts you to constants (at least in C it does), but there is no such restriction with match.
Now, your first case you have h :: t - the :: is called a "cons", another term from functional programming. When you create a new List from another List via a prepend, you can use the :: operator to do it.
Example:
val oldList = List(1, 2, 3)
val newList = 0 :: oldList // newList == List(0, 1, 2, 3)
In Scala, operators that end with a : are really a method of the right hand side, so 0 :: oldList is the equivalent of oldList.::(0) - the 0 :: oldList is syntactic sugar that makes it easier to read.
We could've defined oldList like
val oldList = 1 :: 2 :: 3 :: Nil
where Nil represents an empty List. Breaking this down into steps:
3 :: Nil is evaluated first, creating the equivalent of a List(3) which has head 3 and empty tail.
2 is prepended to the above list, creative a new list with head 2 and tail List(3).
1 is prepended, creating a new list with head 1 and tail List(2, 3).
The resulting List of List(1, 2, 3) is assigned to the val oldList.
Now when you use :: to pattern match you essentially decompose a List into a head and tail, like the reverse of how we created the List above. Here when you do
l match {
case h :: t => ...
}
you are saying decompose l into a head and tail if possible. If you decompose successfully, you can then use these h and t variables to do whatever you want.. typically you would do something like act on h and call the recursive function on t.
One thing to note here is that your code will not compile.. you do an if (h > n) 0 but there is no explicit else so what happens is your code looks like this to the compiler:
if (h > n) 0
else { }
which has type AnyVal (the common supertype of 0 and "nothing"), a violation of your Int guarentee - you're going to have to add an else branch with some failure value or something.
The second case _ => is like a default in the switch, it catches anything that failed the head/tail decomposition in your first case.
Your code essentially does this:
Take the l List parameter and see if it can be decomposed into a head and tail.
If it can be, compare the head against (what I assume to be) a variable in the outer scope called n. If it is greater than n, the function returns 0. (You need to add what happens if it's not greater)
If it cannot be decomposed, the function returns 0.
This is called pattern matching. It's like a switch statement, but more powerful.
Some useful resources:
http://www.scala-lang.org/node/120
http://www.codecommit.com/blog/scala/scala-for-java-refugees-part-4