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