CPSS 51091-1 Homework 1 (due 2/23) Section 2.1.7 (Page19) 2.1.1 b: - 5.0-4.2/1.4; val it = 2.0 : real 2.1.1 d: - "foo"^"bar"^""; val it = "foobar" : string 2.1.1 f: - if 6<10 then 6.0 else 10.0; val it = 6.0 : real 2.1.1 h: - 0xab<123; val it = false : bool 2.1.2 b: if 2<3 then 4 Conditional expressions must always have an else branch. 2.1.2 d: 6+7 DIV 2 "DIV" is a misspelling of the infix operator "div". DIV is not defined in the default environment. 2.1.2 f: 1.0<2.0 or 3>4 The infix boolean disjunction operator is "orelse" so this should be: 1.0<2.0 orelse 3>4 2.1.2 h: 123. In the syntax for decimal numbers, the decimal point (period) must be followed by a digit. 2.1.3: (if interpreting 2.1.3 b as just 2.1.3) "\t\"\\\\\\\" stands for the double-quote character, \\\n\ \\t\\which otherwise would be interpreted \\\n\ \\t\\as the string ender.\"\n"; 2.1.4 b: (if interpreting 2.1.3 b as 2.1.4 b) if E then F else false Section 2.2.5 (Page 26) 2.2.1 b: - floor(~123.45); val it = ~124 : int 2.2.1 c: - ceil(123.45); val it = 124 : int 2.2.1 f: chr 120; val it = #"x" : char 2.2.1 h: (could also use round, or trunc instead of floor) - chr(floor 97.0); val it = #"a" : char 2.2.1 i: - str #"Z"; val it = "Z" : string 2.2.2 b: if true then 5+6 else 7.0 Else and then branches have different types (int and real). fixes: if true then 5+6 else 7 if true then 5.0+6.0 else 7.0 2.2.2 d: - chr (~1); uncaught exception Chr This is not a type error, but an argument out of range error (chr accepts only nonnegative ints) which raises a runtime exception when executed. 2.2.2 f: - chr(#"a"); stdIn:1.1-8.5 Error: operator and operand don't agree [tycon mismatch] operator domain: int operand: char in expression: chr #"a" chr takes an int, not a character. Fix: chr 97; 2.2.2 g: - if 0 then 1 else 2; stdIn:50.1-50.19 Error: test expression in if is not of type bool [literal] test expression: int in expression: if 0 then 1 else 2 The condition of an if expression must have type bool, not int. Fix: if false then 1 else 2; Section 2.3.5 (Page 33) 2.3.1 b: 7Dwarves Not an identifier (starts with a digit) 2.3.1 d: 'SnowWhite' A type variable (starts with apostrophy) 2.3.1 f: hurrah! Not an identifier (alphanumeric identifiers can't contain "!") 2.3.1 h: '123 not an identifier (in a type variable, apostrophy must be followed by a letter) 2.3.2 - val a = 3; val a = 3 : int - val b = 98.6; val b = 98.6 : real - val a = "three"; val a = "three" : string - val c = a^str(chr(floor(b))); val c = "threeb" : string - (a,b,c); val it = ("three",98.6,"threeb") : string * real * string The variables a,b,c are bound and have types string,real, and string respectively. The binding of a as 3 has been "shadowed" by the second binding to the string "three". Section 2.4.7 (Page 42) 2.4.1 b: - hd([3,4,5]); val it = 3 : int 2.4.1 d: - explode("foo"); val it = [#"f",#"o",#"o"] : char list 2.4.1 f: - "c"::["a","t"]; val it = ["c","a","t"] : string list 2.4.1 h: - concat ["c","a","t"]; val it = "cat" : string 2.4.2 b: - hd []; stdIn:6.1-6.6 Warning: type vars not generalized because of value restriction are instantiated to dummy types (X1,X2,...) uncaught exception Empty raised at: smlnj/init/pervasive.sml:194.19-194.24 We'll discuss the first warning later. The function hd raises the Empty exception if it is applied to an empty list. Don't do this! Better to use a case expression, as in case [] of [] => 0 (* default value of the expected element type *) | x::xs => x of course, this is silly since the case dispatch will obviously use the first rule, so this simplifies to 0. But this is a better form to use whenever you are tempted to apply hd to an unknown argument. 2.4.2 d: - explode ["bar"]; stdIn:1.1-2.3 Error: operator and operand don't agree [tycon mismatch] operator domain: string operand: string list in expression: explode ("bar" :: nil) The explode function expects a string, not a string list. Fix: explode "bar". 2.4.2 f: - ["r"]::["a","t"]; stdIn:1.1-2.4 Error: operator and operand don't agree [tycon mismatch] operator domain: string list * string list list operand: string list * string list in expression: ("r" :: nil) :: "a" :: "t" :: nil Cons (::) expects an 'a and an 'a list as arguments, and here it is given a string list and a string list. Fix: "r"::["a","t"]; 2.4.2 h: - 1@2; stdIn:1.1-1.4 Error: operator and operand don't agree [literal] operator domain: 'Z list * 'Z list operand: int * int in expression: 1 @ 2 The infix append function @ is given two ints as arguments, while it wants two lists (of the same type). Fix: [1]@[2] 2.4.3 b: [[1,2],nil,[3]] : int list list 2.4.3 d: ([#"a",#"b"],[nil,[1,2,3]]) : char list * int list list 2.4.4: (1,2) : int * int, (a 2-tuple) (1,2,3) : int * int * int (a 3-tuple) [1,2] : int list [1,2,3] : int list So the first two are of different types, while that last two are of the same type (int list). 2.4.5 b: [(1,#"a")] : (int * char) list 2.4.5 d: (((1,3),[true,false],3.14),(2.0,"abc")) 2.4.5 f: (2.3, [[[[1]]]]) 2.4.6: - fun f s = hd(explode s); val f = fn : string -> char - f "a"; val it = #"a" : char This will blow up for the empty string (how?). Better would be: - fun f s = = (case explode s = of nil => raise Fail "empty string" = | x :: _ => x); val f = fn : string -> char - f ""; uncaught exception Fail [Fail: empty string] raised at: stdIn:15.24-15.43 Chapter 3 Section 3.1.6 (Page 52) 3.1.1 b: fun f(a,b,c) = if a < b then if a < c then a else c else if b < c then b else c 3.1.1 d: fun r(a,b,c) = (c,b,a) 3.1.1 f: fun cycle [] = [] | cycle (y as [x]) = y | cycle (x::xs) = xs @ [x] 3.1.2 b: fun f(a,b,c) = if a < b then if a < c then a::(if b < c then [b,c] else [c,b]) else [c,a,b] else if b < c then b::(if a 8 3.1.3 d: g(5) + a => 10 3.1.3 f: g(f(7)) => 17 Section 3.2.5 (Page 64) 3.2.1 b: fun repeat 0 f x = x | repeat n f x = repeat (n-1) f (f x) fun cyclen i l = repeat i cycle l 3.2.1 d: fun length nil = 0 | length (_::xs) = 1 + length xs 3.2.1 e: fun exp(x,0) = 1.0 | exp(x,n) = x * exp(x,n-1) 3.2.2 (a) from "c+1", c must be an int since 1: int and both arguments of + must have the same type. (b) thus the first branch of the outermost if must be an int (c+1), so the second branch must also be an int. (c) The second branch is the if expression "if a>b then c else b+d" and it must have type int, implying that the two branch expressions c and b+d must be of type int. (d) Since b+d is of type int, b and d must be of type int. (3) Since in the boolean expression a=b b is now known to be an int, it follows that a must also be an int, since the two arguments of equality must have the same type. Thus a,b,c,d are all ints. 3.2.3 b: if a