Haskell 2 Functions and Patterns

Download Report

Transcript Haskell 2 Functions and Patterns

Haskell II
Functions and patterns
26-Jul-16
Data Types







Int
+ - * / ^ even odd
Float + - * / ^ sin cos pi truncate
Char
ord chr isSpace isUpper …
Bool
&& || not
Lists
: ++ head tail last init take
Tuples fst snd
Polymorphic:
< <= == /= => > show
User-Defined Data Types





User-defined data types
data Color = Red | Blue
toString Red
= "red"
toString Blue
= "blue"
data Tree a =
Leaf a | Branch (Tree a) (Tree a)
Can be tricky to use
It’s all about types!



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"
"abc" :: [Char]





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']
['a', 'b', 'c'] :: [Char]
GHCi> ['a', 'b', 'c'] == "abc"
True
More type definitions

GHCi> :t ["ab", "cd"]
["ab", "cd"] :: [[Char]]


GHCi> :t []
[] :: [a]


Here, a is a “type variable”—[] could be a list of any type
GHCi> :t [[]]
[[]] :: [[a]]


[[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
head :: [a] -> a

head takes a list of any type a and returns a single value of type a
Type restrictions

GHCi> :t even
even :: Integral a => a -> Bool



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")
(5, 'a', "abc") :: Num t => (t, Char, [Char])


(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

GHCi> :t mod
mod :: Integral a => a -> a -> a



GHCi> mod 20 6
2
GHCi> 20 `mod` 6
2
Functions in Haskell take a single argument



a -> a -> a associates as (a -> a) -> a
GHCi> (mod 20) 6
2
GHCi> :t (mod 20)
(mod 20) :: Integral a => a -> a
Types of higher-order functions




GHCi> :t map
map :: (a -> b) -> [a] -> [b]
GHCi> :t flip
flip :: (a -> b -> c) -> b -> a -> c
GHCi> flip map [1, 2, 3, 4] even
[False,True,False,True]
GHCi> :t flip map
flip map :: [a] -> (a -> b) -> [b]
compare this with
map :: (a -> b) -> [a] -> [b]
Assorted Syntax






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] -> [a]
Layout

Grouping is done by indentation, not by braces or
parentheses


The first nonblank character following where, let, or
of determines the starting column


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

Make sure your text editor replaces tabs with spaces
Infinite Lists







[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

Functions are “first-class objects”

Functions can be assigned
 Functions can be passed as parameters
 Functions can be stored in data structures
 There are operations on functions
But functions can’t be tested for equality


Theoretically very hard!
Anonymous Functions


Form is \ parameters -> body
Example:
\x y -> (x + y) / 2



\
x
is pronounced “lambda”
and y are the formal parameters
inc x = x + 1


the
the
this is shorthand for
inc = \x -> x + 1
add x y = x + y

this is shorthand for
add = \x y -> x + y
Currying





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

7.0
Slicing


Functions may be “partially applied”
inc x = x + 1


add x y = x + y


can be defined instead as inc = (+ 1)
can be defined instead as add = (+)
negative = (< 0)
Point free style

Functions that take parameters (“points”) can be written as
functions with implicit parameters
GHCi> let square_all
 GHCi> square_all [1,
[1,4,9,16,25]
 GHCi> let square_all
 GHCi> square_all [1,
[1,4,9,16,25]
 GHCi> let square_all
 GHCi> square_all [1,
[1,4,9,16,25]



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



map :: (a -> b) -> [a] -> [b]
applies the function to all elements of the list
Prelude> map odd [1..5]


[True,False,True,False,True]
Prelude> map (* 2) [1..5]

[2,4,6,8,10]
filter



filter :: (a -> Bool) -> [a] -> [a]
Returns the elements that satisfy the test
Prelude> filter even [1..10]


[2,4,6,8,10]
Prelude> filter (\x -> x>3 && x<10) [1..20]

[4,5,6,7,8,9]
iterate



iterate :: (a -> a) -> a -> [a]
f x returns the list [x, f x, f f x, f f f x, …]
Prelude> take 8 (iterate (2 *) 1)


[1,2,4,8,16,32,64,128]
Prelude> iterate tail [1..3]


[[1,2,3],[2,3],[3],[],
*** Exception: Prelude.tail: empty list
foldl



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]


94
94 = 100 - 1 - 2 - 3
foldl1



foldl1 :: (a -> a -> a) -> [a] -> a
Same as: foldl f (head x) (tail x)
Prelude> foldl1 (-) [100, 1, 2, 3]


94
Prelude> foldl1 (+) [1..100]

5050
flip



flip :: (a -> b -> c) -> b ->a -> c
Reverses first two arguments of a function
Prelude> elem 'o' "aeiou"


Prelude> flip elem "aeiou" 'o'


True
True
Prelude> (flip elem) "aeiou" 'o'

True
Function composition with (.)




(.) :: (a -> b) -> (c -> a) -> (c -> b)
(f . g) x
is the same as
f (g x)
double x = x + x
quadruple = double . double
doubleFirst = (* 2) . head
Main> quadruple 3
12
Main> doubleFirst [3..10]
6
span


span :: (a -> Bool) -> [a] -> ([a], [a])
Break the lists into two lists



Main> span (<= 5) [1..10]


those at the front that satisfy the condition
the rest
([1,2,3,4,5],[6,7,8,9,10])
Main> span (< 'm') "abracadabra"

("ab","racadabra")
break


break :: (a -> Bool) -> [a] -> ([a], [a])
Break the lists into two lists



those at the front that fail the condition
the rest
Main> break (== ' ') "Haskell is neat!"

("Haskell"," is neat!")
Function Definition I



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

Haskell is superb at inferring the types of functions


However: All experienced Haskell programmers do explicitly state the
type of each function


Using Hadley-Milner type inference
Doing so catches almost all programming errors!
Haskell programming is all about getting the types right
Function Definition II




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



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





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





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

However, the pattern may specify a list of arbitrary length
Pattern Types II



(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]

2
Pattern Types III




“As-patterns” have the form w@pattern
When the pattern matches, the w matches the whole of
the thing matched
firstThree all@(h:t) = take 3 all
Main> firstThree [1..10]

[1,2,3]
Pattern Types IV



(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


15
This is the only arithmetical pattern; it does not
generalize to any other pattern
Advantages of Haskell


Extremely concise
Easy to understand





no, really!
No core dumps
Polymorphism improves chances of re-use
Powerful abstractions
Built-in memory management
Disadvantages of Haskell


Unfamiliar
Slow

because compromises are less in favor of the machine
quicksort
quicksort [] = []
quicksort (x:xs) =
quicksort [y | y <- xs, y < x] ++
[x] ++
quicksort [y | y <- xs, y >= x]
The End