The purpose of this part of the homework assignment is to make sure that you have all the tools you need for the semester. Before beginning this exercise, read the web pages about installing the course software.
The file nucleic.ml contains a rather complicated test program. I don't really know what it does, but we can use it to check your installation.
All of the following ML code does what it is supposed to do, but it is difficult to read. Rewrite the following ML expressions so that they follow the style guide.
let abc(x:bool) (y:bool) (z:bool) : bool = if x then if y then true else if (x && z) then true else false else false let t(b:bool) (x:float) : float = match b with false -> cos(x) *. cos(x) | true -> (sin(x)+. 1.0) *. (sin(x) +. 1.0) let arithmetic(x1:(float*float)*float) (x2:(float*float)*float):float*float*float = let a = fst (fst x1) in let b = snd (fst x1) in let c = snd x1 in let d = fst (fst x2) in let e = snd (fst x2) in let f = snd x2 in ((((((b*.f) -. (c*.e)), ((c*. d) -. (a*.f) ), ((a*.e)-.(b*.d)))))) let rec max (l: int list) curr : int = match l with [] -> curr | (hd :: tl) -> if hd > curr then max tl hd else max tl curr let reverse (l:int list) : int list = let rec reverse_aux (l: int list) (acc: int list) : int list = if l=[] then acc else reverse_aux (List.tl l) ((List.hd l) :: acc) in reverse_aux l []
Here is a grammar for core-ML expressions that we talked about in class:
expr ::= value | var | expr { expr }+ | expr binary-op expr | prefix-op expr | if expr then expr else expr | let [rec] let-binding in expr | (expr) binary-op ::= + | * | - | && | || prefix-op ::= not | - let-binding ::= pattern = expr | var {pattern}+ :type = expr pattern ::= var | constant | _ | (pattern) | (pattern : type)
Are the following expressions syntactically correct according to this definition? Why or why not? Typing them into O'Caml will not always help you because O'Caml will accept more terms than this grammar does.
a)let x = 3b)
let add (x:int) (y:int) = x + y in add 2c)
3 + 4 * 5d)
let count (x:int) :int = if x = 0 then 0 else count 1 + (x - 1) in count 3
Here is a subset of the grammar for the Scheme language that is used in EOPL.
exp ::= var // Variables | integer // Integers | (lambda (var) exp) // Function definition | (exp exp) // Application of a function to an argument | #t // true | #f // false | (if exp exp exp) // First exp is test, // second is then branch, third is else | (binary-op exp exp) | (prefix-op exp) | (let (var exp) exp) // local binding | (letrec (var exp) exp) // recursive binding binary-op ::= + | * | - | and | or prefix-op ::= - | not
The striking feature about Scheme is that, except for variables and values, every expression must be enclosed by parentheses.
a) Write the Scheme expression that corresponds to the following ML expression:
let x = 3 in let y z = x in if true then (y 4) + (y 5) else y 6
b) Is this grammar ambiguous? If so, give an example of an ambiguous expression. If not, describe why not.
ML Programming from EOPL 1.2.4
Define, debug and test the folling procedures. Include your test cases with your solution. For these exercises, there is no need to check that the input matches the description.
a)(* duple n x returns a list containing n copies of x * for example: * duple 2 3 return [3;3] * duple 4 ("ho","ho") returns * [ ("ho","ho"); ("ho","ho"); ("ho","ho"); ("ho","ho")] *)b)
(* invert lst returns a list with each pair reversed. * for example: * invert [("a",1);("a",2)] returns [(1,"a"),(2,"a")] *)c)
(* filter pred lst returns the list of those elements in * list that satisfy pred. * for example: * filter odd? [0;1;2;3;4] return [1;3] *)d)
(* find pred lst returns the first element of the list that satisfies the predicate. Because no element may do so, the answer is returned in an option. *)e)
(* every pred lst returns false if any element of lst * fails to satisfy pred. *)f)
(* list_set lst n x returns a list like lst, except that * the nth element (using zero-based indexing) is x. * for example: * list_set [1;2;3;4] 2 8 returns [1;2;8;4] * list_set [1;2;3] 5 10 returns [1;2;3] * You can assume n will be >= 0. *)g)
(* merge lon1 lon2, where lon1 and lon2 are lists of numbers sorted in * ascending order, returns a sorted list of all the numbers in lon1 and * lon2. For example: * merge [1;4] [1;2;8] returns [1;1;2;4;8] *)h)
(* bst is the representation of a binary search tree. In a node of this tree, the numbers contained in the left subtree are smaller than the int at the node, and the numbers in the right subtree are greater. *) type bst = N of int * bst * bst | L type dir = Left | Right (* path n bst returns a list of Lefts and Rights, showing how to find the node containing n. If n is found at the root, return []. You may assume that the number exists in the tree. Use "failwith" for the case that cannot happen. for example: path 17 (N (14, N(7, L, N(12, L, L)) N(26, N(20, N(17, L,L), L) N(31,L,L)))) returns Some [Right; Left; Left] *)