Slide 1

Slide 1 text

Haskell: Pure Functional Programming Steffen Jost Munich 3. September 2013

Slide 2

Slide 2 text

About myself Dr Steffen Jost [email protected] 2010– “Wissenschaftlicher Mitarbeiter” at LMU, chair for theoretical computer science (Prof. Hofmann) 2005–2010 Research Fellow, St Andrews, Scotland 2002–2005 PhD student, LMU Munich, Bavaria 1995–2002 Diploma Mathematics, TU Darmstadt, Hessia Research Focus: Automated Program Analysis Type Systems Formal Methods Functional Programming

Slide 3

Slide 3 text

Haskell vs. Mathematics Haskell is general-purpose programming language. Haskell is not replacement for computer algebra systems. However, math-specific libraries exist, like for any other language. Arbitrary-precision integers built-in Int vs. Integer Arbitrary-precision rational numbers built-in List-comprehension looks like Set-comprehension Syntax often motivated by mathematics Mathematics studies ways of abstract thinking, programming is a form abstract thinking.

Slide 4

Slide 4 text

Haskell is good for you Haskell may reduces the cost of software development: Focus on what to compute, not how Fast development of fast code Concise, yet readable code – makes it easier to maintain and to verify Strongly typed: if it compiles, it works – reduces testing Parallelism is easy I learned Haskell a couple of years ago, having previously programmed in Python and (many) other languages. Recently, I’ve been using Python for a project (. . . ), and find my Python programming style is now heavily influenced (for the better, I hope ;-) by my Haskell programming experience. (Graham Klyne, Haskell-Wiki) However: Many true are for all functional languages!

Slide 5

Slide 5 text

Problems with Functional Languages / Haskell Completely different way of thinking Programmers must relinquish micro-control, hence machine-oriented optimisation becomes difficult Many functional features now available in non-declarative languages GC, HO Fkt., Anonyme Fkt., etc. Strongly typed: lots of errors until compilation succeeds Lack of commercial support (IDE, Debugger,. . . ) Programmers usually reject restrictions, however: “with great power comes great ability to shoot oneself in the foot” Restrictions beneficial for multi-person projects, and functional programming seems to be on the rise again.

Slide 6

Slide 6 text

What is different about Haskell? Haskell is pure! No assignment No side effects Evaluation order does not matter ⇒ equational reasoning suffices Haskell is strongly typed Haskell is white-space sensitive Many tutorial/documentation online available Haskell is named after logician Haskell Curry (1900-82). Haskell is just a standard; different Implementations available. Main implementation: Haskell Platform consisting of Libraries, Interpreter and Compiler (GHC = Glasgow/Glorious Haskell Compiler)

Slide 7

Slide 7 text

Referential Transparency Value of identifiers (variables) never change One expression always evaluates to the same value No side effects! ⇒ enhances modularity, code locally comprehensible Simplifies testing and verification ⇒ equational reasoning Order of evaluation is irrelevant ⇒ optimisation, lazy evaluation, parallelism Persistence & Sharing: Changing a data structure requires copying, but unchanged parts can always be referenced ⇒ efficient Algorithms possible, but different (Okasaki) Many other functional Languages are impure and allow imperative updates z.B. F#, Scala, SML, OCaml, Erlang

Slide 8

Slide 8 text

Haskell is pure Function definition through equations: double1 x = x + x -- Function with 1 Argument foo x y z = x + y * double z -- with 3 Arguments add = \x y -> x + y -- Anonymous Fn. 2 Arguments twice f x = f x x -- Higher-order function double2 y = twice (+) y double3 = twice (+) -- Partial application Function application through white-space Left-associative: f x y z == ((f x) y) z Infix-to-Prefix with Parenthesis: (+) 1 2 == 1 + 2 Prefix-to-Infix with Backticks: add 1 2 == 1 ‘add‘ 2 User-definable infixes,∗ e.g. low-precedence right-associative infix $ defined by ($) f x = f x just saves parenthesis: double1 $ 1 + 2 == double1 (1 + 2) ∗Infixes may not start with letter or digit, infix-constructors must start with :

Slide 9

Slide 9 text

Function definitions in Haskell foo :: Type1 -> Type2 -> Type3 -> ResultType foo var1 var2 var3 = expr1 Typdeclaration (optional, typenames always in upper-case) Functionname (must appear in the same column) Argument names Body is a single expression Case-distinction through pattern matching Refine cases through boolean pattern guards First matching branch is evaluated (top-to-bottom) Local definitions may be written underneath

Slide 10

Slide 10 text

Function definitions in Haskell foo :: Type1 -> Type2 -> Type3 -> ResultType foo var1 var2 var3 = expr1 Typdeclaration (optional, typenames always in upper-case) Functionname (must appear in the same column) Argument names Body is a single expression Case-distinction through pattern matching Refine cases through boolean pattern guards First matching branch is evaluated (top-to-bottom) Local definitions may be written underneath

Slide 11

Slide 11 text

Function definitions in Haskell foo :: Type1 -> Type2 -> Type3 -> ResultType foo var1 var2 var3 = expr1 Typdeclaration (optional, typenames always in upper-case) Functionname (must appear in the same column) Argument names Body is a single expression Case-distinction through pattern matching Refine cases through boolean pattern guards First matching branch is evaluated (top-to-bottom) Local definitions may be written underneath

Slide 12

Slide 12 text

Function definitions in Haskell foo :: Type1 -> ... -> Type3 -> ResultType foo var_1 ... var_n = expr1 Typdeclaration (optional, typenames always in upper-case) Functionname (must appear in the same column) Argument names Body is a single expression Case-distinction through pattern matching Refine cases through boolean pattern guards First matching branch is evaluated (top-to-bottom) Local definitions may be written underneath

Slide 13

Slide 13 text

Function definitions in Haskell foo :: Type1 -> ... -> Type3 -> ResultType foo var_1 ... var_n = expr1 Typdeclaration (optional, typenames always in upper-case) Functionname (must appear in the same column) Argument names Body is a single expression Case-distinction through pattern matching Refine cases through boolean pattern guards First matching branch is evaluated (top-to-bottom) Local definitions may be written underneath

Slide 14

Slide 14 text

Function definitions in Haskell foo :: Type1 -> ... -> Type3 -> ResultType foo var_1 ... var_n = expr1 Typdeclaration (optional, typenames always in upper-case) Functionname (must appear in the same column) Argument names Body is a single expression Case-distinction through pattern matching Refine cases through boolean pattern guards First matching branch is evaluated (top-to-bottom) Local definitions may be written underneath

Slide 15

Slide 15 text

Function definitions in Haskell foo :: Type1 -> ... -> Type3 -> ResultType foo pat_1 ... pat_n = expr1 foo pat21 ... pat2n = expr2 foo pat31 ... pat3n = expr3 Typdeclaration (optional, typenames always in upper-case) Functionname (must appear in the same column) Argument names Body is a single expression Case-distinction through pattern matching Refine cases through boolean pattern guards First matching branch is evaluated (top-to-bottom) Local definitions may be written underneath

Slide 16

Slide 16 text

Function definitions in Haskell foo :: Type1 -> ... -> Type3 -> ResultType foo pat_1 ... pat_n = expr1 foo pat21 ... pat2n | grd211, ..., grd21i = expr21 | grd221, ..., grd22i = expr22 foo pat31 ... pat3n Typdeclaration (optional, typenames always in upper-case) Functionname (must appear in the same column) Argument names Body is a single expression Case-distinction through pattern matching Refine cases through boolean pattern guards First matching branch is evaluated (top-to-bottom) Local definitions may be written underneath

Slide 17

Slide 17 text

Function definitions in Haskell foo :: Type1 -> ... -> Type3 -> ResultType foo pat_1 ... pat_n = expr1 foo pat21 ... pat2n | grd211, ..., grd21i = expr21 | grd221, ..., grd22i = expr22 foo pat31 ... pat3n | grd311, ..., grd31k = expr31 | grd321, ..., grd32l = expr32 Typdeclaration (optional, typenames always in upper-case) Functionname (must appear in the same column) Argument names Body is a single expression Case-distinction through pattern matching Refine cases through boolean pattern guards First matching branch is evaluated (top-to-bottom) Local definitions may be written underneath

Slide 18

Slide 18 text

Function definitions in Haskell foo :: Type1 -> ... -> Type3 -> ResultType foo pat_1 ... pat_n = expr1 foo pat21 ... pat2n | grd211, ..., grd21i = expr21 | grd221, ..., grd22i = expr22 foo pat31 ... pat3n | grd311, ..., grd31k = expr31 | grd321, ..., grd32l = expr32 where idA = exprA idB = exprB Typdeclaration (optional, typenames always in upper-case) Functionname (must appear in the same column) Argument names Body is a single expression Case-distinction through pattern matching Refine cases through boolean pattern guards First matching branch is evaluated (top-to-bottom) Local definitions may be written underneath

Slide 19

Slide 19 text

Haskell Expressions Function application through whitespace: f x Anonymous function abstraction: \x -> e Conditional: if b then x else y Pattern-Match: guards useable as on top- level match case e of p1 -> e1 p2 | g1 -> e2-1 | g2 -> e2-2 p3 -> e3 Local definitions: allows function definitions always mutual recursive white-space sensitive: indent-to-right: previous line continues indent-exact: new local definition indent-to-left: let concluded let x = e1 y a b = e2 z = e3 in e4

Slide 20

Slide 20 text

Examples {- This is a comment. - Anything after -- is also a comment. -} show_signed :: Int -> String show_signed i | i>=0 = "+" ++ show i -- Concatenation by infix ++ | otherwise = show i printPercent :: Double -> String printPercent x = leadZero ++ (show roundPercent) ++ "%" where roundPercent :: Double roundPercent = (fromIntegral $ round $ 1000.0*x) / 10.0 leadZero = if rx < 10.0 then "0" else ""

Slide 21

Slide 21 text

Haskell is strongly typed Well-typed programs can’t go wrong! (Milner, 1978) Never type errors at runtime! Errors are recognised at compile time No runtime type checks allow faster execution Types = Documentation Type names always in upper-case No hassel: GHC almost always infers all types Basic types: Char, Int, Integer, Double, Real, Rational,. . . Functiontypes: Int -> Int, (Int -> Int) -> (Int -> Int),. . . Algebraic Datatypes: Tupels, Enums, Lists, Records,. . .

Slide 22

Slide 22 text

Function Types double :: Integer -> Integer double x = x + x foo :: Int -> Int -> Int -> Int foo x y z = x + y * double z twice :: (Int -> Int -> Int) -> Int -> Int twice f x = f x x Funktionstyps are right-associative foo :: Int -> (Int -> (Int -> Int)) to allow partial application cf. “currying” foo 42 :: Int -> (Int -> Int) foo 42 3 :: Int -> Int

Slide 23

Slide 23 text

Tuples addpair :: (Int,Int) -> Int addpair (0,y) = y addpair (x,y) = x+y swap :: (Int,Char) -> (Char,Int) swap (x,y) = (y,x) snd3 :: (Bool,String,Double) -> (String) snd3 (_,s,_) = s Both type and value written using ( , , , ) 0-tuple () referred to as unit-type () Size of tuples is fixed: A function mapping n-tuple to n + 1-tuple for arbitrary n cannot be written due to the strong typing constraints (template haskell allows this)

Slide 24

Slide 24 text

Lists reverse :: [Char] -> String -- reverse [1,2,3] == [3,2,1] reverse [] = [] reverse (h:t) = reverse t ++ [h] concat :: [[Int]] -> [Int] -- concat [[1,2],[3,4]] == [1,2,3,4] Lists are written using [ , , , ] “Cons”-operator is infix (:) :: a -> [a] -> [a] Syntactic sugar for lists: [1,2,3,4] -- shorthand for 1:2:3:4:[] [’c’..’g’] -- evaluates to "cdefg" [1,3..10] -- evaluates to [1,3,5,7,9] List comprehension similar notated to math. set-compreh. [ (x,z) | x <- [1,3..5], y <- [0..x], even y, let z = y+1 ] evaluates to [(1,1),(3,1),(3,3),(5,1),(5,3),(5,5)]

Slide 25

Slide 25 text

Enumerations and Arbitrary Recursive Datatypes data Bool = True | False data Day = Mon | Tue | Wed | Thu | Fri | Sat | Sun next :: Day -> Day next Mon = Tue next Tue = Wed ... Constructors always start with upper-case Constructors may be defined in infix notation Constructors may take arguments: data Person’ = Man String Int | Woman String Double data IntList = Nil | Cons Int IntList -- recurive

Slide 26

Slide 26 text

Records data Person = Mann { name:: String, age :: Int } | Frau { name:: String, height:: Double} p1 = Mann { name = "Alfred", age = 77 } p2 = Frau "Lagertha" undefined p3 = p2 { height = 1.77 } -- p3 points to name of p2 p3 = let p1 = p1 { age = age p1 + 1} -- no update just shadowing in p1 Pattern matching may be partial: isWoman :: Person -> Bool isWoman Frau {} = True isWoman _ = False Projections are automatically defined: name :: Person -> String alter :: Person -> Int

Slide 27

Slide 27 text

Polymorphism Function types might carry type parameters, always lower-case: flip :: (a -> b -> c) -> b -> a -> c flip f x y = f y x Constructors may be parameterised as well: data Maybe b = Just b | Nothing data List a = Cons a (List a) | Nil head :: [a] -> Maybe a head [] = Nothing head (h:_) = Just h map :: (a -> b) -> [a] -> [b] map _ [] = [] map f (x:xs) = f x : map f xs Type safety is still ensured: entities of unknown type may only be passed on different type parameters may be of different types

Slide 28

Slide 28 text

Type Classes (Interfaces) Haskell’s response to overloading, dynamic dispatch, etc. A type class specifies a set of functions: class Eq a where (==), (/=) :: a -> a -> Bool -- two functions required (/=) x y = not $ x == y -- default implementation Datatypes may implement these interfaces, we say “type x is an instance of class y”: instance Eq Person (Mann n1 a1) == (Mann n2 a2) = n1 == n2 && a1 == a2 (Frau n1 g1) == (Frau n2 g2) = n1 == n2 && g1 == g2 _p1 == _p2 = False Polymorphic parameters may be restricted to one or more classes: groupBy :: (a -> a -> Bool) -> [a] -> [[a]] -- explicit group :: Eq a => [a] -> [[a]] -- overloading groupBy parametric polymorphism: always uses same code group ad-hoc polymorphism: code depends on runtime type The class mechanism still ensures complete type safety!

Slide 29

Slide 29 text

Type Classes (Interfaces) GHC may automatically infer instance for simple classes: data Day = Mon | Tue | Wed | Thu | Fri | Sat | Sun deriving (Eq, Ord, Enum, Bounded) data Person’ = Mann’ String Int | Frau’ String Double deriving (Eq, Show) It is also possible to define derived instance definitions: instance (Eq a) => Eq [a] where [] == [] = True (x:xs) == (y:ys) = x == y && xs == ys _xs == _ys = False If we can compare entities of type a, then we also know how to compare lists containing type a

Slide 30

Slide 30 text

Haskell is lazy Most Haskell implementations are lazily evaluated, i.e. any needed expression is evaluated at most once. Speeds up evaluation: map double $ map double $ map double [1..10] iterates only once over the list ignores errors in unused code segments: > let x = map (10/) [10,5,2,0,undefined,4,1] > x!!5 2.5 > x [1.0,2.0,5.0,Infinity,*** Exception: Prelude.undefined Allows dealing with “infinite” data > take 10 [1..] [1,2,3,4,5,6,7,8,9,10] > let x = [1..3] ++ x > take 10 $ x [1,2,3,1,2,3,1,2,3,1]

Slide 31

Slide 31 text

Haskell is lazy Lazy evaluation allows circular program definitions: fibs :: [ Integer ] -- List of all Fibonacci numbers fibs = 1 : 1 : (zipWith (+) fibs (tail fibs )) {- zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] -} fib :: Int -> Integer fib n = fibs !! n -- memoisation already included! Allpws seperation of data from control flow: Specify how Fibonacci numbers are calculated Decide how many elsewhere Every Fibonacci calculated at most once per program run Problem: may lead to memory leaks Problem: often cited as hindrance to understand execution

Slide 32

Slide 32 text

I/O Problem: I/O essentially just side-effects, but Haskell allows no side-effects! Solution: Monads Basic Idea: I/O functions receive an argument symbolizing the world state, change this state, and return the modified world state. Implementing such a torch-relay is tedious, hence it is hidden behind syntactic sugar. Benefits: 2 All side-effects are advertised through the type. Only a function showing a particular side-effect (such as I/O) may call other functions having that side-effect. (thanks to strong typing again)

Slide 33

Slide 33 text

DO Notation Essentially syntactic sugar hiding the torch relay: do me1 -- me1 :: M a me2 -- me2 :: M b x <- me3 -- me3 :: M c, x :: c let y = f x -- f :: c -> d, y :: d when b $ me4 y -- b :: Bool, me4 :: d -> M () z <- forM [1..3] me5 -- me5 :: Int -> M e, z :: [e] return z -- :: M [e] Mimics the imperative style, adequate for I/O Evaluation order automatically observed Effects trickle through as expectes Can always be coded without (and sometimes is)

Slide 34

Slide 34 text

DO Notation DO-Notation’s syntactic sugar revealed: do me1 x <- me2 me3 $ f x could be written as me1 >> me2 >>= \x -> me3 (f x) Binary operators defined in Monad-Class: class Monad m where (>>=) :: forall a b. m a -> (a -> m b) -> m b (>>) :: forall a b. m a -> m b -> m b return :: a -> m a fail :: String -> m a instance Monad IO instance Monad Maybe instance Monad [] ⇒ purely functional code! Not an extension!

Slide 35

Slide 35 text

DO Notation DO-Notation’s syntactic sugar revealed: do me1 x <- me2 me3 $ f x could be written as me1 >> me2 >>= \x -> me3 (f x) Binary operators defined in Monad-Class: class Monad m where (>>=) :: forall a b. m a -> (a -> m b) -> m b (>>) :: forall a b. m a -> m b -> m b return :: a -> m a fail :: String -> m a instance Monad IO instance Monad Maybe instance Monad [] ⇒ purely functional code! Not an extension!

Slide 36

Slide 36 text

I/O example module GoodWorld where import System.IO import System.Time (getClockTime, ClockTime(..)) main :: IO () main = do (TOD seconds n) <- System.Time.getClockTime let greeting = goodX seconds System.IO.putStrLn $ greeting ++ " world!" goodX :: Integer -> String goodX s = | isMorning = "Good morning" | otherwise = "Good day" where isMorning = 12 > s ‘mod‘ (60 * 60 * 24) ⇒ Imperative features like loops and conditionals definable within DO-Notation

Slide 37

Slide 37 text

Example: State Monad Doing the torch-relay with a truly variable state import Data.STRef.Lazy import Control.Monad.ST.Lazy state :: [a] -> [a] state l = runST $ do -- runST :: (forall s. ST s a) -> a ref_l <- newSTRef l l1 <- readSTRef ref_l let l1’ = reverse l1 writeSTRef ref_l l1’ state2 ref_l state2 :: STRef s b -> ST s b state2 ref_l = do -- superfluous "do" and "return" l2 <- readSTRef ref_l return l2 Code who reads or writes state is inside the monad Type System prohibits mixing up references

Slide 38

Slide 38 text

Parallelism and Concurrency No race conditions, if the evaluations order is unimportant, which simplifies pure parallelism: Glasgow parallel Haskell (GpH) Parallelism by inserting two semantic-preserving primitives:: par :: a -> b -> b -- evaluate arguments parallel pseq :: a -> b -> b -- force evaluation but sometimes requires manual forcing of thunks Par Monade Even more simple, but monadic Nested Data Parallelism Provides operations for specialised big data structure, for example Arrays using CUDA Software Transactional Memory (STM) Concurrency, explicit forking using IO-monad, communication via special shared variables, backtracking built-in, but unlike above prone to deadlocks

Slide 39

Slide 39 text

Par Monade do v1 <- new v2 <- new fork $ put v1 (f x) fork $ put v2 (g x) get v1 get v2 return (v1 + v2) Forking is explicit Results will always be fully evaluated Results communicated via write-once IVar’s Parallel computation fully deterministic runPar :: Par a -> a -- teuer fork :: Par () -> Par () -- billig new :: Par (IVar a) get :: IVar a -> Par a put :: NFData a => IVar a -> a -> Par () Partitioning must still be decided by programmer

Slide 40

Slide 40 text

Template Haskell Metaprogramming: Haskell code computes Haskell code ghci -XTemplateHaskell :m + Language.Haskell.TH > let x = [| \x -> x+1 |] x :: Q Exp > runQ x LamE [VarP x_0] (InfixE (Just (VarE x_0)) (VarE GHC.Num.+) (Just > $(x) 3 4 Quasi-Quoting: Code within Oxford-brackets [| |] becomes data Splicing: Data representing code becomes code again $( ) Nesting possible Q monad deals with bookkeeping, e.g. fresh identifiers

Slide 41

Slide 41 text

Template Haskell {-# LANGUAGE TemplateHaskell -#} import Language.Haskell.TH projNI :: Int -> Int -> ExpQ -- generic projection I-th element projNI n i = lamE [pat] rhs where pat = tupP (map varP xs) rhs = varE (xs !! (i - 1)) xs = [ mkName $ "x" ++ show j | j <- [1..n] ] $(projNI 4 3) (’a,’b’,’c’,’d’) -- evaluiert zu ’c’ Code of projNI executed at compile time! Usage $(projNI) may only occur in another module.

Slide 42

Slide 42 text

Template Haskell can also process other languages . . . let jSkillCases t = mconcat [jShowiSkill i t | i <- heroTypeList ] let widget = do toWidget [lucius| -- CSS .itemSelector { width: 11em; height: 13em; } |] addScriptRemote "http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js" toWidget [julius| -- JavaScript function Aendern () { var tc = document.getElementById(’#{fvId htypeView}’); switch (tc.value) { ^{jSkillCases} } } document.getElementById(’#{fvId htypeView}’).setAttribute(’onchange’,’Aendern()’); |] forM_ heroTypeList (\i -> toWidget [julius| -- JavaScript function Show#{show i}Skill () { document.getElementById(’heroImage’).setAttribute(’class’,’#{displayHero i}’); document.getElementById(’SkillAtag’).innerHTML = ’#{displayHeroSkill i 1}’; } |]) [whamlet| --HTML #{fvLabel aliasView} # ^{fvInput aliasView} . . . Yesod Framework

Slide 43

Slide 43 text

Links and Literature Haskell Tools Haskell Platform haskell.org Standard Libraries haskell.org/ghc/docs/latest/html/libraries Haskell Online Tutorials School of Haskell www.fpcomplete.com/school 2013 Learn You a Haskell for Great Good learnyouahaskell.com 2010 by Miran Lipovaˇ ca Real World Haskell book.realworldhaskell.org/read 2008 by Bryan O’Sullivan, Don Stewart, John Goerzen A Gentle Introduction To Haskell www.haskell.org/tutorial 2000 by Paul Hudak, John Peterson, Joseph Fasel (Links clickable)