Practical Practical An introduction to functional programming July 21, 2011
Contents Practical
Practical is fun, and that s what it s all about! Even if seems strange to you at first, don t give up. Learning is almost like learning to program for the first time all over again. It s fun, and it forces you to think differently. Miran Lipovača
is a purely functional programming language. You tell the computer what stuff is. The factorial of a number is the product of every integer from 1 to that number. This operation can be expressed as a function: ghci> let factorial n = product [1..n] You can t set a variable to one value and then set it to something else later on. A function has no side effects. The only thing a function can do is calculate something and return the result. Referential transparency: If a function is called twice with the same parameters, it s guaranteed to return the same result both times. Practical
Practical has strong types. ghci> let x = 1 :: Int ghci> let y = 1 :: Double ghci> x + y Couldn t match expected type... has static types. ghci> True && "False" Couldn t match expected type... s combination of strong and static typing makes it impossible for type errors to occur at runtime.
Practical has type inference. ghci> let factorial n = product [1..n] ghci> :type factorial factorial :: (Num t, Enum t) => t -> t is lazy. ghci> True length [1..] > 0 True is elegant and concise. qsort :: (Ord a) => [a] -> [a] qsort [] = [] qsort (x:xs) = qsort (filter (<= x) xs) ++ [x] ++ qsort (filter (> x) xs) is novel, powerful, and fun.
GHC (The Glasgow Compiler) Practical The Glasgow Compiler is a state-of-the-art, open source, compiler and interactive environment for the functional language. GHC has two main components: GHCi (ghci) is an interactive interpreter and debugger. GHC (ghc) is an optimizing compiler. The Glasgow Compiler (GHC). www.haskell.org/ghc
The Platform Practical : Batteries included. The Platform is a comprehensive, robust development environment for programming in. The platform makes it trivial to get up and running with a full development environment. Comprehensive, robust, and cutting edge. Current stable release: 2011.2.0.1 (April 2011) The Platform. hackage.haskell.org/platform
GNU Emacs Practical GNU Emacs is an extensible, customizable text editor, and more. The current stable release is 23.3. GNU Emacs. www.gnu.org/software/emacs mode is a major Emacs mode for editing source code. mode. projects.haskell.org/haskellmode-emacs
The community Practical The Communities and Activities Report. in industry. in education. in research. and mathematics. Planet, The Monad.Reader..... www.haskell.org
Frag Practical
Monadius Practical
Agda, Darcs, and xmonad Practical Agda is a dependently typed functional programming language and a proof assistant. wiki.portal.chalmers.se/agda Darcs is a free, open source code management system. darcs.net xmonad is a dynamically tiling X11 window manager that is written and configured in. xmonad.org
xmonad Practical
Practical www.haskell.org
Example () 1. $ ghci Prelude> "" "" 2. Prelude> putstr "\n" Prelude> :quit 3. $ cat hello.hs main :: IO () main = putstrln "" $ ghc hello.hs $./a.out $ ghci Practical
Example (Factorial) factorial :: (Integral a) => a -> a 1. factorial n = if n == 0 then 1 else n * factorial (n - 1) 2. factorial 0 = 1 factorial n = n * factorial (n - 1) 3. factorial n n == 0 = 1 otherwise = n * factorial (n - 1) 4. Prelude> let factorial n = product [1..n] Prelude> factorial 16 20922789888000 Practical
Practical Prelude> :set prompt "ghci> " Examples (Basic arithmetic) ghci> 16 + 18 34 ghci> 11 * 6 66 ghci> (-) 2010 1922 88 ghci> 9 / 8 1.125
Examples (The order of operations) ghci> (34 * 88) - 2991 1 ghci> 34 * 88-2991 1 ghci> 34 * (88-2991) -98702 Practical Examples (Negative numbers) ghci> 9 * -8 Precedence parsing error ghci> 9 * (-8) -72
Examples (Boolean algebra) ghci> True && False False ghci> False True True ghci> not (False && True) True Practical Examples (Equality and inequality) ghci> 5 == 5 True ghci> "hello" /= "hello" False
ghci> :set +t Examples (Mathematical constants) ghci> pi 3.141592653589793 it :: Double ghci> e... Not in scope: e ghci> exp 1 2.718281828459045 it :: Double Practical ghci> :unset +t
Examples (Functions) ghci> succ 18 19 ghci> min 16 18 + max 6 11 + 5 32 ghci> succ 2 * 10 30 ghci> succ (2 * 10) 21 ghci> div 10 2 5 ghci> 10 div 2 5 Practical
Practical
Types Practical ghci> :t f f :: Char ghci> :t "foo" "foo" :: [Char] Common types Int Integers 1, 2, 3, 4,... Integer Integers 1, 2, 3, 4,... Float Floating point numbers 1.0, 2.0, 3.0, 4.0,... Double Floating point numbers 1.0, 2.0, 3.0, 4.0,... Bool Booleans True, False Char Unicode characters a, b, c, d,... In, every expression and function has a type.
Lists Practical Examples ghci> ["David","Roger"] ["David","Roger"] ghci> [True,False,"True"] Couldn t match expected type... ghci> "Hello" ++ ", " ++ "world!" "" ghci> [ h, e ] ++ [ l, l, o ] "hello" ghci> [1..5] ++ [5,4..1] [1,2,3,4,5,5,4,3,2,1]
Lists Practical Examples ghci> a :[ b.. z ] "abcdefghijklmnopqrstuvwxyz" ghci> 1:2:3:4:5:[] [1,2,3,4,5] ghci> [ a.. y ]: z Couldn t match expected type... ghci> [[1..5],[5,4..1]] [[1,2,3,4,5],[5,4,3,2,1]]
Lists Examples ghci> [3,4,2] < [3,4,3] True ghci> [3,4,2] < [2,4] False ghci> [3,2,1] > [2,10,100] True ghci> "gilmour" > "waters" False ghci> [3,4,2] == [3,4,2] True ghci> [[],[]] == [[],[],[]] False Practical
Lists Practical Examples (List operations) ghci> head [1..5] ghci> last [1..5] 1 5 ghci> init [1..5] ghci> tail [1..5] [1,2,3,4] [2,3,4,5] ghci> null [] ghci> null [[]] True False ghci> take 3 [1..5] ghci> take 100 [1..5] [1,2,3] [1,2,3,4,5] ghci> drop 3 [1..5] ghci> drop 100 [1..5] [4,5] []
Lists Practical Examples (List operations) ghci> maximum [1,11,22] 22 ghci> minimum [1,11,22] 1 ghci> sum [1..10] 55 ghci> product [10,9..1] 3628800 ghci> a elem "hello" False
Lists Practical Examples (Ranges) ghci> [ a.. z ] "abcdefghijklmnopqrstuvwxyz" ghci> [7,14..7*10] [7,14,21,28,35,42,49,56,63,70] ghci> [70,63..7] [70,63,56,49,42,35,28,21,14,7] ghci> [0.5,0.7..1.0] [0.5,0.7,0.8999999999999999,1.0999999999999999]
Lists Practical Examples (List comprehensions) ghci> [x * 2 x <- [50..100], x mod 7 == 0] [112,126,140,154,168,182,196] pairs :: [a] -> [b] -> [(a,b)] pairs xs ys = [(x,y) x <- xs, y <- ys] perms :: (Eq a) => [a] -> [[a]] perms [] = [[]] perms xs = [x:ps x <- xs, ps <- perms (xs \\ [x])]
Tuples Practical Examples ghci> :t (True,"True", t ) (True,"True", t ) :: (Bool, [Char], Char) ghci> fst (1,2) 1 ghci> snd (1,2) 2 ghci> :t zip zip :: [a] -> [b] -> [(a, b)] ghci> zip [1..] [ a.. d ] [(1, a ),(2, b ),(3, c ),(4, d )]
Example (linecount) $ cat lc.hs main :: IO () main = interact linecount where linecount :: String -> String linecount input = show (length (lines input)) ++ "\n" $ runhaskell lc.hs < lc.hs 6 $ runhaskell lc.hs < hello.hs 2 Practical
Algebraic types Practical Algebraic data type definitions are introduced by the keyword data, followed by the name of the type, an equals sign and then the constructors of the type being defined. The simplest sort of algebraic type is defined by enumerating the elements of the type. Examples 1. data Temp = Cold Hot 2. data Season = Spring Summer... 3. data Bool = True False
Algebraic types Practical Examples 1. type Name = String type Age = Int data Person = Person Name Age 2. data Shape = Circle Float Rectangle Float Float deriving (Eq,Ord,Show,Read)
Pattern matching Practical Pattern matching is used to specify patterns to which some data should conform and to deconstruct the data according to those patterns. Example (sayme) sayme :: Int -> String sayme 1 = "One!" sayme 2 = "Two!" sayme 3 = "Three!" sayme 4 = "Four!" sayme 5 = "Five!" sayme x = "Not between 1 and 5"
Pattern matching Practical Example (length) length returns the length of a finite list. length :: [a] -> Int length [] = 0 length (_:xs) = 1 + length xs ghci> length [] 0 ghci> length [1..5] 5
Pattern matching Example (Numerical expressions) data Expr = Lit Int Add Expr Expr Sub Expr Expr eval :: Expr -> Int eval (Lit n) = n eval (Add e1 e2) = (eval e1) + (eval e2) eval (Sub e1 e2) = (eval e1) - (eval e2) Practical : Define a function eqexpr :: Expr -> Expr -> Bool that compares two numerical expressions for equality.
Guards Practical Patterns are used to check if the values passed to a function are constructed in a certain way. Guards are used to check if some property of those passed values is true or false. Example (sayme) sayme :: Int -> String sayme n n == 1 = "One!" n == 2 = "Two!" n == 3 = "Three!" n == 4 = "Four!" otherwise = "Not between 1 and 5"
Lazy evaluation Practical will compute only what it really must. Examples (Infinite lists) 1. ones :: [Int] ones = 1 : ones 2. powers :: Int -> [Int] powers n = [n^x x <- [0..]] 3. pythagtriples :: [(Int,Int,Int)] pythagtriples = [(x,y,z) z <- [2..], y <- [2..z - 1], x <- [2..y - 1], x*x + y*y == z*z]
Lazy evaluation Example (The sieve of Eratosthenes) primes :: [Integer] primes = sieve [2..] sieve :: [Integer] -> [Integer] sieve (x:xs) = x : sieve [y y <- xs, y mod x > 0] Practical memberord :: (Ord a) => [a] -> a -> Bool memberord (x:xs) n x < n = memberord xs n x == n = True otherwise = False
Practical
Polymorphism A value is polymorphic if, depending on the context where it is used, it can take more than one type. Example (last) ghci> :type last last :: [a] -> a ghci> last [1,9,8,9] 9 ghci> last "Ummagumma" a Practical Parametric polymorphism is when a function s type signature allows various arguments to take on arbitrary types, but the types must be related to each other in some way.
Polymorphism Ad hoc polymorphism (or overloading) is when the possible types are limited and must be individually specified before use. Example (show) ghci> :type show show :: (Show a) => a -> String ghci> show 22 "22" ghci> show 2.2 "2.2" Practical In, ad hoc polymorphism is achieved by type classes.
Recursion Practical Recursion is a way of defining functions in which a function calls itself. Example (reverse) reverse returns the elements of a list in reverse order. reverse :: [a] -> [a] reverse [] = [] reverse (x:xs) = reverse xs ++ [x] ghci> reverse [1,2,3,4,5] [5,4,3,2,1] ghci> reverse "man o nam" "man o nam"
Recursion Practical Example (repeat) repeat takes an element and returns an infinite list composed of that element. repeat :: a -> [a] repeat x = x : repeat x ghci> let ones = repeat 1 ghci> take 5 ones [1,1,1,1,1] ghci> replicate 5 1 [1,1,1,1,1]
Recursion Practical Example (zip) zip takes two lists and zips them together. zip :: [a] -> [b] -> [(a,b)] zip (x:xs) (y:ys) = (x,y) : zip xs ys zip = [] ghci> zip [1,2,3] ["one","two"] [(1,"one"),(2,"two")]
Recursion Practical Example (quicksort) quicksort :: (Ord a) => [a] -> [a] quicksort [] = [] quicksort (x:xs) = let left = [a a <- xs, a <= x] right = [a a <- xs, a > x] in quicksort left ++ [x] ++ quicksort right ghci> quicksort ("the quick brown fox " ++ "jumps over the lazy dog") " abcdeeefghhijklmnoooopqrrsttuuvwxyz"
Higher-order functions Practical functions can take functions as parameters and return functions as return values. Curried functions and partial application In, all functions take only one argument. ghci> max 4 5 ghci> (max 4) 5 5 5 ghci> let max4 = max 4 ghci> max4 5 5 max :: (Ord a) => a -> a -> a can also be written as max :: (Ord a) => a -> (a -> a)
Higher-order functions Practical Example (zipwith) zipwith generalizes zip by zipping with the function given as the first argument. zipwith :: (a b c) [a] [b] [c] zipwith f (x:xs) (y:ys) = f x y : zipwith f xs ys zipwith _ = [] ghci> zipwith (+) [1,2,3,4,5] [1,2,3,2,1] [2,4,6,6,6] ghci> zipwith (*) (replicate 5 2) [1..] [2,4,6,8,10]
Higher-order functions Practical Example (flip) flip takes a function and returns a function like the original, but with the first two arguments flipped. flip :: (a -> b -> c) -> b -> a -> c flip f y x = f x y ghci> zip [1..5] "aeiou" [(1, a ),(2, e ),(3, i ),(4, o ),(5, u )] ghci> flip zip [1..5] "aeiou" [( a,1),( e,2),( i,3),( o,4),( u,5)]
Higher-order functions Practical Example (map) map f xs is the list obtained by applying f to each element of xs. map :: (a -> b) -> [a] -> [b] map _ [] = [] map f (x:xs) = f x : map f xs ghci> map (+ 2) [1,2,3,2,1] [3,4,5,4,3] ghci> map even [1..5] [False,True,False,True,False]
Higher-order functions Example (filter) filter takes a predicate and a list, and returns the list of elements that satisfy the predicate. filter :: (a -> Bool) -> [a] -> [a] filter _ [] = [] filter p (x:xs) p x = x : filter p xs otherwise = filter p xs ghci> filter (> 2) [1,2,3,2,1] [3] ghci> filter even [1..5] [2,4] Practical
Higher-order functions Practical Example (quicksort) quicksort :: (Ord a) => [a] -> [a] quicksort [] = [] quicksort (x:xs) = quicksort left ++ [x] ++ quicksort right where left = filter (<= x) xs right = filter (> x) xs
Higher-order functions Lambdas Lambdas are anonymous functions that are used when a function is needed only once. ghci> map (\x -> x + 2) [1,2,3,2,1] [3,4,5,4,3] Example (flip) Practical flip :: (a -> b -> c) -> b -> a -> c flip f = \x y -> f y x ghci> zip [1..5] "aeiou" [(1, a ),(2, e ),(3, i ),(4, o ),(5, u )] ghci> flip zip [1,2,3,4,5] "aeiou" [( a,1),( e,2),( i,3),( o,4),( u,5)]
Higher-order functions Examples (Application operator) ($) :: (a -> b) -> a -> b f $ x = f x ghci> sum $ filter (> 10) $ map (* 2) [2..10] 80 ghci> map ($ 3) [(4 +),(10 *),(^ 2),sqrt] [7.0,30.0,9.0,1.7320508075688772] Practical Examples (Function composition) (.) :: (b -> c) -> (a -> b) -> a -> c f. g = \x -> f (g x) ghci> map (negate. abs) [1,2,-3,-5,4] [-1,-2,-3,-5,-4]
Practical 1. Understanding the problem. 2. Designing the program. 3. Writing the program. 4. Looking back. Simon Thompson. Where do I begin? A problem solving approach in teaching functional programming. 1997.
Example (The maximum of three integers) 1. Understanding the problem. maxthree :: Int -> Int -> Int -> Int 2. Designing and writing the program. maxtwo :: Int -> Int -> Int maxtwo a b a <= b = b otherwise = a maxthree a b c b <= a && c <= a = a a <= b && c <= b = b otherwise = c maxthree a b c = maxtwo (maxtwo a b) c 3. Looking back. Practical
Learn you a for great good! Practical
Learn you a for great good! Practical 1. Read chapters 1-6 of the tutorial Learn you a for great good! 2. Answer the following questions. What do you like/dislike about functional programming? What do you like/dislike about? What do you think of the tutorial?... Miran Lipovača. Learn you a for great good! No Starch Press, 2011. learnyouahaskell.com
Practical
Practical Miran Lipovača. Learn you a for great good! No Starch Press, 2011. learnyouahaskell.com Bryan O Sullivan, John Goerzen, and Don Stewart. Real world. O Reilly, 2008. book.realworldhaskell.org Simon Thompson. : The craft of functional programming. Addison-Wesley, 2011. www.haskellcraft.com