Haskell II Functions and patterns 05 Jan22 Data

  • Slides: 38
Download presentation
Haskell II Functions and patterns 05 -Jan-22

Haskell II Functions and patterns 05 -Jan-22

Data Types n n n n Int + - * / ^ even odd

Data Types n n n n Int + - * / ^ even odd Float + - * / ^ sin cos pi truncate Char ord chr is. Space is. Upper … Bool && || not Lists : ++ head tail last init take Tuples fst snd Polymorphic: < <= == /= => > show

User-Defined Data Types n n n User-defined data types data Color = Red |

User-Defined Data Types n n n User-defined data types data Color = Red | Blue to. String Red = "red" to. String Blue = "blue" data Tree a = Leaf a | Branch (Tree a) Can be tricky to use

It’s all about types! n n n Getting the types right is critical to

It’s all about types! n n n Getting the types right is critical to programming in Haskell In GHCi, : type x or : t x will tell you the type of x GHCi> : t "abc" : : [Char] n n n The : : can be read as “has the type” [Char] is the representation for “list of char” Is "abc" really a list of characters? GHCi> : t ['a', 'b', 'c'] : : [Char] GHCi> ['a', 'b', 'c'] == "abc" True

More type definitions n GHCi> : t ["ab", "cd"] : : [[Char]] n n

More type definitions n GHCi> : t ["ab", "cd"] : : [[Char]] n n GHCi> : t [] [] : : [a] n n Here, a is a “type variable”—[] could be a list of any type GHCi> : t [[]] : : [[a]] n n [[Char]] is a list of lists of characters = a list of strings [[a]] is a list of lists, all of which have the same type GHCi> : t head : : [a] -> a n head takes a list of any type a and returns a single value of type a

Type restrictions n GHCi> : t even : : Integral a => a ->

Type restrictions n GHCi> : t even : : Integral a => a -> Bool n n n Integral a is a type restriction—it says a must be some Integral type The -> indicates a function; in this case, a function from some type a (restricted to be integral) to a Boolean. GHCi> : t (5, 'a', "abc") : : Num t => (t, Char, [Char]) n n (5, 'a', "abc") is a tuple consisting of a Numeric type t, a Character, and a string (list of Char) Unlike lists, tuples can (and often do) contain values of different types

Types of functions n GHCi> : t mod : : Integral a => a

Types of functions n GHCi> : t mod : : Integral a => a -> a n n n GHCi> mod 20 6 2 GHCi> 20 `mod` 6 2 Functions in Haskell take a single argument n n n a -> a associates as (a -> a) -> a GHCi> (mod 20) 6 2 GHCi> : t (mod 20) : : Integral a => a -> a

Types of higher-order functions n n GHCi> : t map : : (a ->

Types of higher-order functions n n GHCi> : t map : : (a -> b) -> [a] -> [b] GHCi> : t flip : : (a -> b -> c) -> b -> a -> c GHCi> flip map [1, 2, 3, 4] even [False, True, False, True] GHCi> : t flip map : : [a] -> (a -> b) -> [b] compare this with map : : (a -> b) -> [a] -> [b]

Assorted Syntax n n n Comments are -- to end of line or {-

Assorted Syntax n n n Comments are -- to end of line or {- to -} (these may be nested) Types are capitalized, variables are not Indentation may be used in place of braces Infix operators: + - `mod` `not` Prefix operators: (+) (-) mod not Types: take : : Int -> [a]

Layout n Grouping is done by indentation, not by braces or parentheses n n

Layout n Grouping is done by indentation, not by braces or parentheses n n The first nonblank character following where, let, or of determines the starting column n n Actually, braces can be used, but that’s unusual let x = a + b y = a * b in y / x Every expression in the same group must begin in the same column n Make sure your text editor replaces tabs with spaces

Infinite Lists n n n n [1. . 5] == [1, 2, 3, 4,

Infinite Lists n n n n [1. . 5] == [1, 2, 3, 4, 5] [1. . ] == all positive integers [5, 10. . 32] == [5, 10, 15, 20, 25, 30] [5, 10. . ] == positive multiples of 5 [x*x | x <- [1. . ]] == squares of positive integers [x*x | x <- [1. . ], even x] == squares of positive even integers [(x, y) | x <- [1. . 10], y <- [1. . 10], x < y]

Functions are also data n Functions are “first-class objects” n Functions can be assigned

Functions are also data n Functions are “first-class objects” n Functions can be assigned n Functions can be passed as parameters n Functions can be stored in data structures n There are operations on functions But functions can’t be tested for equality n n Theoretically very hard!

Anonymous Functions n n Form is  parameters -> body Example: x y ->

Anonymous Functions n n Form is parameters -> body Example: x y -> (x + y) / 2 n n n x is pronounced “lambda” and y are the formal parameters inc x = x + 1 n n the this is shorthand for inc = x -> x + 1 add x y = x + y n this is shorthand for add = x y -> x + y

Currying n n n Technique named after Haskell Curry Functions only need one argument

Currying n n n Technique named after Haskell Curry Functions only need one argument Currying absorbs an argument into a function f a b = (f a) b, where (f a) is a curried function (avg 6) 8 n 7. 0

Slicing n n Functions may be “partially applied” inc x = x + 1

Slicing n n Functions may be “partially applied” inc x = x + 1 n n add x y = x + y n n can be defined instead as inc = (+ 1) can be defined instead as add = (+) negative = (< 0)

Point free style n Functions that take parameters (“points”) can be written as functions

Point free style n Functions that take parameters (“points”) can be written as functions with implicit parameters GHCi> let square_all n GHCi> square_all [1, [1, 4, 9, 16, 25] n GHCi> let square_all n GHCi> square_all [1, 4, 9, 16, 25] n n n xs = map (x -> x^2) xs 2, 3, 4, 5] = map (x -> x^2) 2, 3, 4, 5] = map (^2) 2, 3, 4, 5] Point free style can result in easier to read, less cluttered code It can also result in obscure code, so use with care 17

map n n n map : : (a -> b) -> [a] -> [b]

map n n n map : : (a -> b) -> [a] -> [b] applies the function to all elements of the list Prelude> map odd [1. . 5] n n [True, False, True] Prelude> map (* 2) [1. . 5] n [2, 4, 6, 8, 10]

filter n n n filter : : (a -> Bool) -> [a] Returns the

filter n n n filter : : (a -> Bool) -> [a] Returns the elements that satisfy the test Prelude> filter even [1. . 10] n n [2, 4, 6, 8, 10] Prelude> filter (x -> x>3 && x<10) [1. . 20] n [4, 5, 6, 7, 8, 9]

iterate n n n iterate : : (a -> a) -> a -> [a]

iterate n n n iterate : : (a -> a) -> a -> [a] f x returns the list [x, f f f x, …] Prelude> take 8 (iterate (2 *) 1) n n [1, 2, 4, 8, 16, 32, 64, 128] Prelude> iterate tail [1. . 3] n n [[1, 2, 3], [3], [], *** Exception: Prelude. tail: empty list

foldl n n n foldl : : (a -> b -> a) -> a

foldl n n n foldl : : (a -> b -> a) -> a -> [b] -> a foldl f i x starts with i, repeatedly applies f to i and the next element in the list x Prelude> foldl (-) 100 [1. . 3] n n 94 94 = 100 - 1 - 2 - 3

foldl 1 n n n foldl 1 : : (a -> a) -> [a]

foldl 1 n n n foldl 1 : : (a -> a) -> [a] -> a Same as: foldl f (head x) (tail x) Prelude> foldl 1 (-) [100, 1, 2, 3] n n 94 Prelude> foldl 1 (+) [1. . 100] n 5050

flip n n n flip : : (a -> b -> c) -> b

flip n n n flip : : (a -> b -> c) -> b ->a -> c Reverses first two arguments of a function Prelude> elem 'o' "aeiou" n n Prelude> flip elem "aeiou" 'o' n n True Prelude> (flip elem) "aeiou" 'o' n True

Function composition with (. ) n n (. ) : : (a -> b)

Function composition with (. ) n n (. ) : : (a -> b) -> (c -> a) -> (c -> b) (f. g) x is the same as f (g x) double x = x + x quadruple = double. First = (* 2). head Main> quadruple 3 12 Main> double. First [3. . 10] 6

span n n span : : (a -> Bool) -> [a] -> ([a], [a])

span n n span : : (a -> Bool) -> [a] -> ([a], [a]) Break the lists into two lists n n n Main> span (<= 5) [1. . 10] n n those at the front that satisfy the condition the rest ([1, 2, 3, 4, 5], [6, 7, 8, 9, 10]) Main> span (< 'm') "abracadabra" n ("ab", "racadabra")

break n n break : : (a -> Bool) -> [a] -> ([a], [a])

break n n break : : (a -> Bool) -> [a] -> ([a], [a]) Break the lists into two lists n n n those at the front that fail the condition the rest Main> break (== ' ') "Haskell is neat!" n ("Haskell", " is neat!")

Function Definition I n n n Functions are defined with = fact : :

Function Definition I n n n Functions are defined with = fact : : Int -> Int -- explicit type fact n = if n == 0 then 1 else n * fact (n - 1) There is no requirement that you explicitly state the type of each function you define n Haskell is superb at inferring the types of functions n n However: All experienced Haskell programmers do explicitly state the type of each function n n Using Hadley-Milner type inference Doing so catches almost all programming errors! Haskell programming is all about getting the types right

Function Definition II n n Functions are usually defined by cases fact : :

Function Definition II n n Functions are usually defined by cases fact : : Int -> Int fact n | n == 0 = 1 | otherwise = n * fact (n - 1) fact : : Int -> Int fact n = case n of 0 -> 1 n -> n * fact (n - 1) These are equivalent definitions

Function Definition III n n n You can separate the cases with “patterns” fact

Function Definition III n n n You can separate the cases with “patterns” fact : : Int -> Int fact 0 = 1 fact n = n * fact (n - 1) How does this work?

Pattern Matching n n n Functions cannot in general be overloaded But they can

Pattern Matching n n n Functions cannot in general be overloaded But they can be broken into cases Each case must have the same signature fact : : Int -> Int -- explicit signature fact 0 = 1 fact n = n * fact (n - 1) fact 5 won’t match the first, but will match the second

Pattern Types I n n n A variable will match anything A wildcard, _,

Pattern Types I n n n A variable will match anything A wildcard, _, will match anything, but you can’t use the matched value A constant will match only that value Tuples will match tuples, if same length and constituents match Lists will match lists, if same length and constituents match n However, the pattern may specify a list of arbitrary length

Pattern Types II n n n (h: t) will match a nonempty list whose

Pattern Types II n n n (h: t) will match a nonempty list whose head is h and whose tail is t second (h: t) = head t Main> second [1. . 5] n 2

Pattern Types III n n “As-patterns” have the form w@pattern When the pattern matches,

Pattern Types III n n “As-patterns” have the form w@pattern When the pattern matches, the w matches the whole of the thing matched first. Three all@(h: t) = take 3 all Main> first. Three [1. . 10] n [1, 2, 3]

Pattern Types IV n n n (n+k) matches any value equal to or greater

Pattern Types IV n n n (n+k) matches any value equal to or greater than k; n is k less than the value matched silly (n+5) = n Main> silly 20 n n 15 This is the only arithmetical pattern; it does not generalize to any other pattern

Advantages of Haskell n n Extremely concise Easy to understand n n no, really!

Advantages of Haskell n n Extremely concise Easy to understand n n no, really! No core dumps Polymorphism improves chances of re-use Powerful abstractions Built-in memory management

Disadvantages of Haskell n n Unfamiliar Slow n because compromises are less in favor

Disadvantages of Haskell n n Unfamiliar Slow n because compromises are less in favor of the machine

quicksort [] = [] quicksort (x: xs) = quicksort [y | y <- xs,

quicksort [] = [] quicksort (x: xs) = quicksort [y | y <- xs, y < x] ++ [x] ++ quicksort [y | y <- xs, y >= x]

The End

The End