The purpose of this assignment is to provide some experience with writing simple SML programs. In particular, recursion and pattern matching with supplied datatypes will be tested.
Note: Some of these exercises produce a nested object. To make sure that the printer for SML shows you all of it, you can raise the print depth of the compiler by typing the following at SML's prompt.
Compiler.Control.Print.printDepth := 100;After this, the compiler's printer will print structures up to depth 100.
[Points 40] Mobiles are simple structures often hanging from ceilings involving internal beams with strings attached to weights or other beams. We will model a mobile with the following data type.
datatype mobile = node of mobile * mobile | leaf of int;Some examples of mobiles are the following:
val m1 = node (node(leaf 2, leaf 2), node(leaf 2, leaf 2)); val m2 = node(node(leaf 2, node(leaf 1, leaf 1)), node(leaf 2,leaf 2)); val m3 = node(node(node(leaf 2, leaf 2), node(leaf 2, node(leaf 1, leaf 1))), node(leaf 4, leaf 4)); val m4 = node(node(node(leaf 2, leaf 2), node(leaf 1, node(leaf 1, leaf 1))), node(leaf 4, leaf 4));The weight of a mobile is the sum of the all the weights (integers) at the leaves of the mobile. A mobile is balanced if it is either a leaf or if it is a node then the weight of the left and right subtrees must be the same and these subtrees must be balanced.
Write a function
balance_weight : mobile -> bool * intthat takes a mobile and returns a pair. The first component of the pair is true if the mobile is balanced and otherwise it is false. The second component is the weight of the mobile. For instance, we should have the following evaluations:
- balance_weight m1; val it = (true,8) : bool * int - balance_weight m2; val it = (true,8) : bool * int - balance_weight m3; val it = (true,16) : bool * int - balance_weight m4; val it = (false,15) : bool * int
Please write the solution without defining any auxiliary function and in such a way that each node of the mobile is visited only once (i.e. recursion over the mobile is done only once). Solutions which do not satisfy this requirement will get, at most, 30 points (for this exercise).
[Points 40] Consider the following datatype which we shall use to represent simple algebric expressions.
datatype exp = Var of string | Num of real | Opr of string * exp * exp;Some examples of simple expressions of this type would be
val e1 = Var"x"; val e2 = Num(3.2); val e3 = Opr("+", Var"x",Num 3.2); val e4 = Opr("+", Opr("*", Num 3.0, Opr("^", Var "x", Num 2.0)), Opr("*", Num 2.0, Var "x"));Write a function deriv of type (exp * string) -> exp, where the first argument is the expression to be differentiated and the second argument is the name of the variable for which the derivative is to be done. In computing the derivate, only use the following derivative rules (assuming here that we are taking the derivative with respect to the variable x).
Dz = 0 if z is a number or a variable different from x Dx = 1 D(u+v) = Du + Dv D(u-v) = Du - Dv D(u*v) = v*Du + u*Dv D(u/v) = (v*Du - u*Dv) / (v^2) D(u^n) = n*(u^(n-1)*Du) where n is a numberFor this exercise you can define auxiliary functions if you want.
Note: When defining this function, it is okay to get a Warning: match nonexhaustive error message here since not all expressions will be given a derivative by these rules. For example, there is no rule for taking the derivative of x ^ x. The result of the derivative does not need to be in "simplified" form. That is, the expression Opr("+", Num 1.0, Num 1.0) can be left (although it's "simplified form" would be Num 2.0). For example, you should compute something like the following:
- deriv (e4,"x"); val it = Opr ("+", Opr ("+",Opr ("*",Opr ("^",Var "x",Num 2.0),Num 0.0), Opr ("*",Num 3.0, Opr ("*",Num 2.0,Opr ("*",Opr ("^",Var "x",Num 1.0),Num 1.0)))), Opr ("+",Opr ("*",Var "x",Num 0.0),Opr ("*",Num 2.0,Num 1.0))) : expSome more examples:
val a1 = Opr("+", Opr("*", Num 3.0, Opr("^", Var "x", Num 2.0) ), Opr("*", Num 2.0, Var "x" ) ); - deriv(a1,"y"); val it = Opr ("+", Opr ("+",Opr ("*",Opr ("^",Var "x",Num 2.0),Num 0.0), Opr ("*",Num 3.0, Opr ("*",Num 2.0,Opr ("*",Opr ("^",Var "x",Num 1.0),Num 0.0)))), Opr ("+",Opr ("*",Var "x",Num 0.0),Opr ("*",Num 2.0,Num 0.0))) : exp **************************************************** val a2 = Opr("+", Opr("*", Var "y", Opr("^", Var "x", Num 2.0) ), Opr("*", Var "x", Var "z" ) ); - deriv(a2,"y"); val it = Opr ("+", Opr ("+",Opr ("*",Opr ("^",Var "x",Num 2.0),Num 1.0), Opr ("*",Var "y", Opr ("*",Num 2.0,Opr ("*",Opr ("^",Var "x",Num 1.0),Num 0.0)))), Opr ("+",Opr ("*",Var "z",Num 0.0),Opr ("*",Var "x",Num 0.0))) : exp **************************************************** val a3 = Opr("-", Opr("/", Opr("^", Var "y", Num 3.0), Num 2.0 ), Opr("/", Var "y", Var "x" ) ); - deriv(a3,"x"); val it = Opr ("-", Opr ("/", Opr ("-", Opr ("*",Num 2.0, Opr ("*",Num 3.0,Opr ("*",Opr ("^",Var "y",Num 2.0),Num 0.0))), Opr ("*",Opr ("^",Var "y",Num 3.0),Num 0.0)), Opr ("^",Num 2.0,Num 2.0)), Opr ("/",Opr ("-",Opr ("*",Var "x",Num 0.0),Opr ("*",Var "y",Num 1.0)), Opr ("^",Var "x",Num 2.0))) : exp
[Points 20] Consider representing just 13 cards of one suit of a deck of playing cards with the following datatype:
datatype card = ace | numbered of int | jack | queen | king;Write a function
smaller : card * card -> boolsuch that smaller(C,D) is true if and only if C is a card that is either the same as D or comes before D (in the usual ordering). Here, aces are the smallest cards, the numbered cards are ordered by their number value. After the numbered cards, jack is the next largest and is followed by the queen. King is the largest card. For example, of the following six expressions
smaller(king,king); smaller(ace, ace); smaller(numbered 6, numbered 9); smaller(queen,numbered 5); smaller(jack,numbered 5); smaller(king, ace);the first three evaluate to true and the remaining three evaluate to false. For this exercise you can define auxiliary functions if you want.
Download this solution frame and fill it in with your definitions. Save it with name XXXX.sml, where XXXX are the last 4 digits of your student id.
The code of the examples above are here. You can download them, then save it with name definitions.sml. Now you can enter sml with the Unix command
/home/users2/sml/bin/smlNow that you are in sml, you can load your code and the definitions, and set the print depth, with the commands
- use "XXXX.sml"; - use "definitions.sml"; - Compiler.Control.Print.printDepth := 100;Now you are ready to test your program. You can try the expressions above. For instance, if you type
- balance_weight m1;you should get the answer
val it = (true,8) : bool * int
Please note the following:.