(* CS:3820, Fall 2016 *) (* Cesare Tinelli *) (* The University of Iowa *) (* F# examples seen in class *) (* Simple types *) 3 + 5 3.0 1.4 + 3.0 "hi" // some operator names are overloaded 1.4 + 3.0 "hi" + " there" // no implicit type conversions 1.4 + 3 // error (* Boolean type *) true not true true && false true || false 4 = 5 // comparison operator, not assignment! 4 < 5 (* Variable binding *) let a = 3 // declares symbolic value a as a synonym for 3 a // evaluates to 3 a = 4 // Boolen expression, not assignment! let b = 4 + a (* Type ascription *) let c:string = 55 // requires c to be of type string let c:float = 7 // type mismatch error // any term can be annotated with a type constraint (4:int) (((4:int) = 1):bool) (* logical operators, conditional expressions *) if 3 < 4 then "yes" else "no" // The if construct is an expression. // It can be seen as a mixfix operator with three arguments: B, T1 and T2 // // if B then T1 else T2 // // B must be of type bool. T1 and T2 must be of the same type. // The type of the whole if is the type of T1 and T2 if 3 < 4 then "yes" else 4 // ill-typed let c = 5 if (c > 0) 10 else 20 // if expressions can go everywhere an expression of can go (if (c > 0) 1 else 0) + 7 let r1 = (if 3 < 4 then "yes" else "no") let r2 = (if 3 < 4 then "yes" else "no") + ", sir" (* tuple types *) (1,3) (3,4,5) (3,"pp",4.3) // note the different types of this tuples (1,2,3) ((1,2),3) (1,(2,3)) ((1,2),3) = (1,2,3) // ill-typed // the empty tuple is a value () // () is the *only* value of type unit // it is used for instance for functions // that are called only for their side effect (* function binding *) let next (n:int):int = n + 1 next // next is bound to a function from int to int next(4) next 4 // more common syntax next next 4 // incorrect syntax: read as ((next next) 4) next (next 4) // correct syntax // input and output types can are inferred automatically let fnext n = n + 1.0 // integer vesion of + used in the absence of additional type info let f x = x + x // Type constraints can be added as needed let double (x : string) = x + x let double x : float = x + x let double (x : int) : int = x + x // functions with unit return type let print_value i = printfn "The value is %i" i // this expression evaluates to () // but also has the side effect of printing // a message on the standard output stream print_value 4 (* Recursive function declarations *) let rec fac n = if n = 0 then 1 else n * fac (n - 1) fac 7 (* Mutually recursive function declarations *) let rec even n = if n = 0 then true else odd (n - 1) and odd n = if n = 0 then false else even (n - 1) (* Let binding visibility *) let a = 5 let f x = a + x f 1 let a = 2 // *new* constant with name // new constant shadows old one a // however, the old one still exists and is unchanged // f was defined using the old a, not the new one f 1 // The scope of a let binder is the rest of the file // unless explicitly reduced with 'in' let q = 3 in q + 1 // ^^^^^ scope of q q // q not defined here let x = 12 // outer x is 12, its scope starts with this line // and extends until the end of the file let r = let x = 3 in x * x // inner x is 9, its scope is only this line x // outer x unchanged // nested declarations shadow less local ones let k = 1 in (let k = 2 in (let k = 3 in printfn "%i" k ); // within scope of each of three lets printfn "%i" k // within scope of first two lets only ); printfn "%i" k // within scope of first let only // function definitions can have local scope too let h x = x + 3 in h 1 // scope of identifier h h // error // this implies that functions can be defined locally // within other functions let f x = let l_square x = x * x in let l_double x = x + x in l_square(x) - l_double(x) f 5 l_square 3 // error