Presentation is loading. Please wait.

Presentation is loading. Please wait.

CSC 580 – Theory of Programming Languages, Spring, 2009 Week 9: Functional Languages ML and Haskell, Dr. Dale E. Parson.

Similar presentations


Presentation on theme: "CSC 580 – Theory of Programming Languages, Spring, 2009 Week 9: Functional Languages ML and Haskell, Dr. Dale E. Parson."— Presentation transcript:

1 CSC 580 – Theory of Programming Languages, Spring, 2009 Week 9: Functional Languages ML and Haskell, Dr. Dale E. Parson

2 ML (so-called meta-language) (SML/NJ at http://www.smlnj.org) ML is a functional language. – Side effects are possible via arrays and ref variables, but using them is not the norm. – No loops, normally code is free of side effects. Unlike Lisp, ML uses strong static typing. – Context sensitive type inference minimizes the amount of explicit typing in the code. – Implicit parametric polymorphism supports generic functions.

3 ML Data Types The usual primitive types Lists, tuples, and structured aggregate types User defined types, modules, and abstraction interfaces for information hiding Immutable bindings for variables and function names Mutable array and ref variable types Strong, static, implicit type inference from context Nested lexical scope using let construct, closures supported

4 Variable bindings are immutable - val a = 5; val a = 5 : int - fun adda(x) = x + a; val adda = fn : int -> int - val a = 6 (* This is a totally different immutable variable! *); val a = 6 : int - fun adda_again(x) = x + a; val adda_again = fn : int -> int - adda(1); val it = 6 : int - adda_again(1); val it = 7 : int

5 Type inference infers object types. Type resolution occurs at compile time - val a = 5; val a = 5 : int - fun adda(x) = x + a; val adda = fn : int -> int - adda; val it = fn : int -> int Implicit parametric polymorphism supports generic functions. - fun identity(x) = x ; (* Unlike Python, everything has a static type. *) val identity = fn : 'a -> 'a(* ‘a is a type variable, similar to a C++ template type.) - identity(4); val it = 4 : int - identity("foo"); val it = "foo" : string

6 Strong, static types. - val a = 8 ; val a = 8 : int - val b = 9.0 ; val b = 9.0 : real - a * b; stdIn:4.1-4.6 Error: operator and operand don't agree [tycon mismatch] operator domain: int * int operand: int * real in expression: a * b

7 Strong, static types continued. - b * a; stdIn:1.1-1.6 Error: operator and operand don't agree [tycon mismatch] operator domain: real * real operand: real * int in expression: b * a - a * floor(b); val it = 72 : int

8 Strong, static typing implies. No variable number of function parameters. No eval function. What implies this concept? No heterogeneous lists. - val l = [1, 2, "a"]; stdIn:5.9-5.20 Error: operator and operand don't agree [literal] operator domain: int * int list operand: int * string list in expression: 2 :: "a" :: nil

9 Higher Order Functions map, reduce and filter Similar to Lisp, Scheme and (later) Python function composition and currying Built into ML using “o” operator (composition) and unparenthesized parameters (currying). Parenthesized parameters constitute a tuple. function parameter evaluation is eager functions are first-class objects (passed as arguments, returned from functions)

10 Examples of composition, curried functions and lambda expressions. ~parson/ThryLang/func/ Function composition built into ML is more powerful and notationally convenient than anything we (or at least I) can define using the language. Likewise for curried functions. The inability to use vararg parameters because of strong static typing limits flexibility. The language constructs are powerful, but overall flexibility and extensibility are less than with dynamically typed languages like Python or Scheme.

11 Comparison to Scheme and Python Functional Programming Strong type inference trades flexibility and certain kinds of extensibility in favor of stronger compile-time error checking. Perspective is compile-time verification of program correctness. Not only are there typically no side effects (as in pure Lisp), but also no chance for type incompatibilities. Type inference minimizes explicit type specification in the code.

12 Other Noteworthy Features PROLOG-like patterns on function variants and data structure variants. Eager evaluation fun returndiv(quotient, divisor) = if divisor <> 0 then quotient else ~1000 ; (* Like a C conditional statement. *) - returndiv(8 div 2, 2); val it = 4 : int - returndiv(8 div 0, 0); uncaught exception Div [divide by zero] raised at: stdIn:5.13-5.16

13 Haskell Haskell has many features similar to ML. tuples, lists, structured data, modules, type inference Haskell is strictly pure functional programming – no side effects – monads hide I/O side effects behind an action abstraction Lazy evaluation is one of the more novel features. Formally, normal order evaluation. Similar to short-circuited boolean expressions and if- then-else control constructs in imperative languages. The unused expressions are never evaluated.

14 Lazy evaluation ~parson/ThryLang/func/hugsdemo.hs returndiv quotient divisor = if (divisor /= 0) then quotient else -1000 Main> returndiv (div 8 2) 2 4 Main> returndiv (div 8 0) 0 -1000 (div 8 0) is never evaluated unless used It may be evaluated once, then the value is cached.

15 Infinite Lists are Generators addfirsttwo (x:y:zs) = x + y ones = 1 : ones from n = n : from (n+1) fromstep n m = n : fromstep (n+m) m Main> addfirsttwo(ones) 2 Main> addfirsttwo(from 7) 15 Main> addfirsttwo(fromstep 10 10) 30 Main> addfirsttwo([ 3.. ]) 7 Main> addfirsttwo([ 3, 6.. ]) 9

16 Lazy Evaluation is a generalization of special purpose mechanisms in imperative languages Similar to short-circuited boolean expressions and if- then-else control constructs in imperative languages. Laziness allows a called function or accessed data structure to decide when to evaluate an expression and possibly bind its value to a parameter. Make the imperative special cases into a general approach to evaluation. Lazy evaluation is a conditional rewrite approach.

17 Conclusions Lisp and Python are good for experimenting with extensibility within a functional programming framework. ML and Haskell are good for type-safe functional programming with powerful builtin mechanisms. Extensibility of the language itself is not well supported in ML and Haskell.


Download ppt "CSC 580 – Theory of Programming Languages, Spring, 2009 Week 9: Functional Languages ML and Haskell, Dr. Dale E. Parson."

Similar presentations


Ads by Google