9/28/09

cs242

Lisp Algol 60

Algol 68

Pascal Kathleen Fisher

ML Modula C++ Reading: “Concepts in Programming Languages” Chapter 5 except 5.4.5 “Real World Haskell”, Chapter 0 and Chapter 1 (http://book.realworldhaskell.org/) Haskell Java

Many other languages: Algol 58, Algol W, Euclid, EL1, Mesa (PARC), Modula-2, Oberon, Modula-3 (DEC), …

 Basic Language of 1960  Simple imperative language + functions  Successful syntax, BNF -- used by many successors real procedure average(A,n);  statement oriented real array A; integer n; No array bounds.  begin … end blocks (like C/Java { … } ) begin  if … then … else real sum; sum := 0;  Recursive functions and stack storage allocation for i = 1 step 1 until n  Fewer ad hoc restrictions than Fortran do  General array references: A[ x + B[3] * y ] sum := sum + A[i];  Type discipline was improved by later languages average := sum/n No “;” here.  Very influential but not widely used in US end;  To n y H o are : “Here is a language so far ahead of its time that it was not only an improvement on its predecessors Set procedure return value by assignment. but also on nearly all of its successors.”

 Question:  Holes in type discipline   Is x := x equivalent to doing nothing? Parameter types can be arrays, but  No array bounds  Interesting answer in Algol:  Parameter types can be procedures, but  No argument or return types for procedure parameters integer procedure p; begin  Some awkward control issues ….  goto out of block requires memory management p := p ….  end; Problems with parameter passing mechanisms  Pass-by-name “Copy rule” duplicates code, interacting badly with side effects Assignment here is actually a recursive call!  Pass-by-value expensive for arrays

1 9/28/09

 Substitute text of actual parameter  Fixed some problems of Algol 60  Unpredictable with side effects!  Eliminated pass-by-name   Example Considered difficult to understand  Idiosyncratic terminology procedure inc2(i, j);  Types were called “modes” integer i, j;  Arrays were called “multiple values” begin begin  i := i+1; k := k+1; Used vW grammars instead of BNF j := j+1 A[k] := A[k] +1  Context-sensitive grammar invented by van Wijngaarden end; end;  Elaborate type system

inc2 (k, A[k]);  Complicated type conversions  Not widely adopted Is this what you expected? Adriaan van Wijngaarden

 Primitive modes . Compound modes  Storage management  int . arrays   real . structures Local storage on stack  char . procedures  Heap storage, explicit alloc, and garbage collection  bool . sets  string . pointers  Parameter passing  compl (complex)  Pass-by-value  bits  bytes  Use pointer types to obtain pass-by-reference  sema (semaphore)   format (I/O) Rich, structured, and Assignable procedure variables  file orthogonal type system is  Follow “orthogonality” principle rigorously a major contribution of Algol 68. A Tutorial on Algol 68 by Andrew S. Tanenbaum

 Designed by Niklaus Wirth (Turing Award)  Array bounds part of type illegal  Revised the type system of Algol procedure p(a : array [1..10] of integer)  Good data-structuring concepts procedure p(n: integer, a : array [1..n] of integer)  records, variants, subranges  Attempt at orthogonal design backfires  More restrictive than Algol 60/68 – Parameter must be given a type  Procedure parameters cannot have higher-order – Type cannot contain variables procedure parameters How could this have happened? Emphasis on teaching?  Popular teaching language . Not successful for “industrial-strength” projects  Simple one-pass . Kernighan: “Why Pascal is not my favorite language” . Left niche for C; niche has expanded!!

Niklaus Wirth

2 9/28/09

ML

 Statically typed, general-purpose programming language  Type safe! Designed by Dennis Ritchie, Turing Award winner, for writing Unix  Compiled language, but intended for interactive use  Evolved from B, which was based on BCPL  Combination of Lisp and Algol-like features  Expression-oriented  B was an untyped language; C adds some checking  Higher-order functions  Garbage collection  Relationship between arrays and pointers  Abstract data types  An array is treated as a pointer to first element  Module system  E1[E2] is equivalent to ptr dereference: *((E1)+(E2))  Exceptions  Pointer arithmetic is not common in other languages  Designed by Turing-Award winner Robin Milner for LCF Theorem Prover  Ritchie quote  Used in textbook as example language  “C is quirky, flawed, and a tremendous success.”

Haskell  Haskell is a programming language that is  Similar to ML: general-purpose, strongly typed, higher-order,  Good vehicle for studying language concepts functional, supports type inference, supports interactive and  Types and type checking compiled use  General issues in static and dynamic typing  Different from ML: lazy evaluation, purely functional core, rapidly evolving type system.  Type inference  Parametric polymorphism  Designed by committee in 80’s and 90’s to unify  Ad hoc polymorphism research efforts in lazy languages.  Control  Haskell 1.0 in 1990, Haskell ‘98, Haskell’ ongoing.  Lazy vs. eager evaluation  “A History of Haskell: Being Lazy with Class” HOPL 3  Tail recursion and continuations  Paul Hudak Simon Precise management of effects Peyton Jones

John Hughes Phil Wadler

 Functional programming will make you think 1,000,000 differently about programming.  Mainstream languages are all about state 10,000

 Functional programming is all about values Practitioners

 Ideas will make you a better in 100 whatever language you regularly use. The quick death 1  Haskell is “cutting edge.” A lot of current Geeks research is done in the context of Haskell. 1yr 5yr 10yr 15yr

3 9/28/09

Threshold of immortality 1,000,000 1,000,000

10,000 10,000 Practitioners Practitioners The complete 100 100 absence of death The slow death

1 1 Geeks Geeks

1yr 5yr 10yr 15yr 1yr 5yr 10yr 15yr

“Learning Haskell is a great way of training yourself to think functionally so you are ready to take full advantage of “I'm already looking at coding C# 3.0 when it comes out” problems and my mental (blog Apr 2007) In Haskell, f :: A → B means for every x ∈ A, perspective is now shifting 1,000,000 back and forth between purely OO and more FP styled solutions” f(x) = some element y = f(x) ∈ B (blog Mar 2007) 10,000 run forever Practitioners

100 The second life? In words, “if f(x) terminates, then f(x) ∈ B.” In ML, functions with type A → B can throw an 1 Geeks exception, but not in Haskell.

1990 1995 2000 2005 2010

 Functions that take other functions as arguments or return as a result are higher-order functions.  Interactive (ghci): read-eval-print  ghci infers type before compiling or executing  Common Examples: Type system does not allow casts or other loopholes!  Map: applies argument function to each element in a collection.  Reduce: takes a collection, an initial value, and a function, and  Examples combines the elements in the collection according to the function. Prelude> (5+3)-2 6 list = [1,2,3] it :: Integer = foldl (\accumulator i -> i + accumulator) 0 list Prelude> if 5>3 then “Harry” else “Hermione” “Harry”  Google uses Map/Reduce to parallelize and distribute it :: [Char] -- String is equivalent to [Char] massive data processing tasks. Prelude> 5==4 False (Dean & Ghemawat, OSDI 2004) it :: Bool

4 9/28/09

 Booleans  Tuples True, False :: Bool if … then … else … --types must match (4, 5, “Griffendor”) :: (Integer, Integer, String)  Integers  Lists 0, 1, 2, … :: Integer [] :: [a] -- polymorphic type +, * , … :: Integer -> Integer -> Integer 1 : [2, 3, 4] :: [Integer] -- infix cons notation  Strings  Records  “Ron Weasley” data Person = Person {firstName :: String, lastName :: String}  Floats hg = Person { firstName = “Hermione”, lastName = “Granger”} 1.0, 2, 3.14159, … --type classes to disambiguate

Haskell Libraries

 Patterns can be used in place of variables ::= | | | …  Anonymous function \x -> x+1 --like Lisp lambda, function (…) in JS  Value declarations  General form  Declaration form = =  Examples 1 1 = … myTuple = (“Flitwick”, “Snape”) 2 2 (x,y) = myTuple = … myList = [1, 2, 3, 4] z:zs = myList  Examples

 Local declarations f (x,y) = x+y --actual parameter must match pattern (x,y) length [] = 0 let (x,y) = (2, “Snape”) in x * 4 length (x:s) = 1 + length(s)

 Apply function to every element of list  Append lists

map f [] = [] append ([], ys) = ys map f (x:xs) = f x : map f xs append (x:xs, ys) = x : append (xs, ys)

map (\x -> x+1) [1,2,3] [2,3,4]  Reverse a list

 Compare to Lisp reverse [] = [] reverse (x:xs) = (reverse xs) ++ [x] (define map (lambda (f xs) (if (eq? xs ()) ()  Questions (cons (f (car xs)) (map f (cdr xs))) )))  How efficient is reverse?  Can it be done with only one pass through list?

5 9/28/09

 Notation for constructing new lists from old: reverse xs = let rev ( [], accum ) = accum myData = [1,2,3,4,5,6,7] rev ( y:ys, accum ) = rev ( ys, y:accum ) in rev ( xs, [] ) twiceData = [2 * x | x <- myData] -- [2,4,6,8,10,12,14]

twiceEvenData = [2 * x| x <- myData, x `mod` 2 == 0] -- [4,8,12]

1 3

2 2 2 2

3 3 1 3 1 1

 Examples  data Color = Red | Yellow | Blue  Recursively defined data structure  elements are Red, Yellow, Blue data Tree = Leaf Int | Node (Int, Tree, Tree) data Atom = Atom String | Number Int Node(4, Node(3, Leaf 1, Leaf 2),  4 elements are Atom “A”, Atom “B”, …, Number 0, ... Node(5, Leaf 6, Leaf 7)) data List = Nil | Cons (Atom, List) 3 5  elements are Nil, Cons(Atom “A”, Nil), … Cons(Number 2, Cons(Atom(“Bill”), Nil)), ...  Recursive function 1 2 6 7  General form data = | … | sum (Leaf n) = n ::= | sum (Node(n,t1,t2)) = n + sum(t1) + sum(t2) Type name and constructors must be Capitalized.

 Define datatype of expressions  Datatype data Exp = Var Int | Const Int | Plus (Exp, Exp) data Exp = Var Int | Const Int | Plus (Exp, Exp) Write (x+3)+ y as Plus(Plus(Var 1, Const 3), Var 2) . Case expression  Evaluation function case e of ev(Var n) = Var n Var n -> … ev(Const n ) = Const n Const n -> … ev(Plus(e1,e2)) = … Plus(e1,e2) -> …  Examples ev(Plus(Const 3, Const 2)) Const 5 Indentation matters in case statements in Haskell.

ev(Plus(Var 1, Plus(Const 2, Const 3))) Plus(Var 1, Const 5)

6 9/28/09

 Haskell is a lazy language

data Exp = Var Int | Const Int | Plus (Exp, Exp)  Functions and data constructors don’t evaluate

ev ( Var n) = Var n their arguments until they need them. ev ( Const n ) = Const n ev ( Plus ( e1,e2 ) ) = cond :: Bool -> a -> a -> a cond True t e = t case ev e1 of cond False t e = e Var n -> Plus( Var n, ev e2) Const n -> case ev e2 of  Var m -> Plus( Const n, Var m) can write control-flow operators Const m -> Const (n+m) that have to be built-in in eager languages. Plus(e3,e4) -> Plus ( Const n, Plus ( e3, e4 )) Plus(e3, e4) -> Plus( Plus ( e3, e4 ), ev e2) (||) :: Bool -> Bool -> Bool Short- True || x = True circuiting False || x = x “or”

isSubString :: String -> String -> Bool  Generate all solutions (an enormous tree) x `isSubString` s = or [ x `isPrefixOf` t | t <- suffixes s ]  Walk the tree to find the solution you want suffixes:: String -> [String] type String = [Char] -- All suffixes of s nextMove :: Board -> Move suffixes[] = [[]] nextMove b = selectMove allMoves suffixes(x:xs) = (x:xs) : suffixes xs where allMoves = allMovesFrom b or :: [Bool] -> Bool A gigantic (perhaps infinite) -- (or bs) returns True if any of the bs is True tree of possible moves or [] = False or (b:bs) = b || or bs

 Basic Types . Patterns . Available on Stanford pod cluster  Unit . Declarations . Handout on course web site on how to use.  Booleans . Functions  Integers . Polymorphism  Or, download: http://haskell.org/ghc .  Strings Type declarations  Interactive: . Type Classes  Reals  ghci intro.hs  Tuples . Monads  Lists . Exceptions  Compiled:  Records  ghc –make AlgolAndHaskell.hs

Demo ghci

7 9/28/09

Te st.Q u ick C h e ck is simply a Haskell (not a “tool”)

 It’s good to write tests as you write code bash$ ghci intro.hs Prelude> :m +Test.QuickCheck  E.g. reverse undoes itself, etc. Prelude Test.QuickCheck> quickCheck prop_RevRev reverse xs = +++ OK, passed 100 tests let rev ( [], z ) = z rev ( y:ys, z ) = rev( ys, y:z ) in rev( xs, [] ) ...with a strange- -- Write properties in Haskell looking type type TS = [Int] -- Test at this type

prop_RevRev :: TS -> Bool Prelude Test.QuickCheck> :t quickCheck prop_RevRev ls = reverse (reverse ls) == ls quickCheck :: Testable prop => prop -> IO ()

Demo QuickCheck

No side effects. At all. Purity makes the interface explicit.

reverse:: [w] -> [w] reverse:: [w] -> [w] -- Haskell  A call to reverse returns a new list; the old  Takes a list, and returns a list; that’s all. one is unaffected. void reverse( list l ) /* C */ prop_RevRev l = reverse(reverse l) == l  Takes a list; may modify it; may modify other  A variable ‘l’ stands for an immutable value, persistent state; may do I/O. not for a location whose value can change.  Laziness forces this purity.

Pure functions are easy to test. Types are everywhere.

prop_RevRev l = reverse(reverse l) == l reverse:: [w] -> [w]  In an imperative or OO language, you have to  Usual static-typing panegyric omitted...  set up the state of the object and the external state it reads or writes  In Haskell, types express high-level design, in  make the call the same way that UML diagrams do, with the advantage that the type signatures are  inspect the state of the object and the external state machine-checked.  perhaps copy part of the object or global state, so  Types are (almost always) optional: type that you can use it in the post condition inference fills them in if you leave them out.

8 9/28/09

 The Haskell wikibook  http://en.wikibooks.org/wiki/Haskell  All the Haskell bloggers, sorted by topic  http://haskell.org/haskellwiki/Blog_articles  Collected research papers about Haskell  http://haskell.org/haskellwiki/Research_papers  Wiki articles, by category  http://haskell.org/haskellwiki/Category:Haskell  Books and tutorials  http://haskell.org/haskellwiki/Books_and_tutorials

9