180 likes | 248 Views
Writing functions in ML. Defining a simple function. MLWorks> fun add (x, y) = x + y; val add : (int * int) -> int = fn Notice what this says: add is a value the type of add is (int * int) -> int the -> denotes a function Therefore, a function is a kind of value!
E N D
Defining a simple function • MLWorks> fun add (x, y) = x + y; • val add : (int * int) -> int = fn • Notice what this says: • add is a value • the type of add is(int * int) -> int • the -> denotes a function • Therefore, a function is a kind of value! • The actual value is abbreviated to fn
Another function definition • MLWorks> fun double x = 2 * x; • val double : int -> int = fn • Why don't we need parentheses around the parameter x? • Every function in ML takes one parameter and returns one result. • The parameter may be a tuple • The result may be a tuple
add again • MLWorks> fun add (x, y) = x + y; • val add : (int * int) -> int = fn • MLWorks> add (7, 3); • val it : int = 10 • MLWorks> add(3.0, 5.0); • Gives a type error; why? • ML is strongly typed, but it can deduce types • If expression could be real or int, default is int
Statements in ML • There are no statements in ML • ML is a purely functional language; it has no side effects*...but ML does have expressions • Every expression has a value * Except for output "statements"--we won't be doing output
The if...then...else expression • ifboolean-expressionthenexpression1elseexpression2 • The else part is required (why?) • because the if expression must have a value • expression1 and expression2 must have the same type • because ML is strongly typed • it needs to know the type of the expression
Using if...then...else • MLWorks> fun max(x, y) = if x > y then x else y; • val max : (int * int) -> int = fn • MLWorks> max (7, 5); • val it : int = 7
Integer division, with remainder • MLWorks> fun divide(x, y) = (x div y, x mod y); • val divide : (int * int) -> (int * int) = fn • MLWorks> divide (20, 3); • val it : (int * int) = (6, 2) • We aren't returning two results, just one--but it's a tuple • Similarly, we're only providing one parameter
Adding vectors • MLWorks> fun addVec ((x1, y1), (x2, y2)) = ((x1 + x2), (y1 + y2)); • val addVec : ((int * int) * (int * int)) -> (int * int) = fn • MLWorks> addVec ((3, 5), (10, 20)); • val it : (int * int) = (13, 25)
LISP-like operations • Recall that ML has the following operations: • hd returns the head of a list • tl returns the tail of a list • :: adds an element to a list • These are essentially the same as CAR, CDR, and CONS in LISP • Can we define CAR, CDR, and CONS in ML?
Redefining LISP • MLWorks> fun car x = hd x; • val car : 'a list -> 'a = fn • MLWorks> fun cdr x = tl x; • val cdr : 'a list -> 'a list = fn • MLWorks> fun cons (x, y) = x :: y; • val cons : ('a * 'a list) -> 'a list = fn • MLWorks> car (cdr [1,2,3,4]); • val it : int = 2
Testing our LISP functions • MLWorks> cons([1,2], [3,4]); • Function applied to argument of wrong typeNear: cons (1 :: 2 :: nil, 3 :: 4 :: nil) Required argument type: (int list * int list list) Actual argument type: (int list * int list) Type clash between int and int list • Elements of list must be same type! • There is no solution (with the ML we know so far)
Trapped in time • MLWorks> val age = 20; • MLWorks> fun older ( ) = age + 1; • MLWorks> older ( ); • val it : int = 21 • MLWorks> val age = 35; • MLWorks> older ( ); • val it : int = 21
ML adds to state, doesn't change it • ML has no "assignment" • val age = 21; associates age with 21 • This age is then used in function older • val age = 35; associates a new age with 35 • The old age goes out of scope • ...but older still refers to the old one
Functions are values, too • MLWorks> fun f x = 2 * x; • MLWorks> fun g x = f (f x); • MLWorks> g 5; • val it : int = 20 • MLWorks> fun f x = 3 * x; • MLWorks> g 5; • val it : int = 20
Debugging functions • You saw that redefining a function does not affect prior uses of that function • Therefore, you can't change a function by changing something it calls • Everything should work OK if you compile all your functions from a file every time • Sometimes you just have to restart ML
It's all in the binding times • ML's approach seems strange, but you have seen it before • x = 5;y = 2 * x;x = x + 1;print "y = ", y; • Would you expect y = 12 to be printed? • Remember, functions are values too!