1. Functions
Sebastian Rettig
Every function in haskell consumes exactly
Every function in haskell consumes exactly
one parameter and returns aa value.
one parameter and returns value.
2. Functional Programming
● No Variables
● Functions only, eventually stored in
Modules
– Behavior do not change, once defined
– → Function called with same parameter
calculates always the same result
● Function definitions (Match Cases)
● Recursion (Memory)
3. Haskell Features
● Pure Functional Programming Language
● Lazy Evaluation
● Pattern Matching and Guards
● List Comprehension
● Type Polymorphism
4. Nice to remember (1)
Typeclasses:
● define properties of the types
● like an interface
– Eq can be compared
– Ord can be ordered (>, <, >=, <=) (extending Eq)
– Show can be shown as string
– Read opposite of Show
– Enum sequentially ordered types (can be enumerated
and usable in List-Ranges ['a'..'e'])
5. Nice to remember (2)
Typeclass-Membership:
1. derive from existing Memberships of used types
data Vector2D = Vector Float Float deriving (Show, Eq)
2. implement Membership by your own
instance Show Vector2D where
show Vector a b = “x: ” ++ [a] ++ “ ; y: ” ++ [b]
6. Curried Functions (1)
● let's look at the Function header again, e.g:
max :: (Ord a) => a -> a -> a
1. we have a Typeclass restriction for Ord
2. we have 2 Parameters of Types, who have a
membership for the Ord Typeclass
3. we have a return value of the same type
● But, why is the syntax not separating the parameters
better from the result set?
7. Curried Functions (2)
● every function in haskell consumes exactly one
parameter and returns a value
● so we could write the function header instead of:
max :: (Ord a) => a -> a -> a
● also in the following way:
max :: (Ord a) => a -> (a -> a)
– max is a function which consumes a parameter and
returns a function
– these function consumes a parameter and returns a
value (the max of both values)
●
→ Partial Application
8. Curried Functions (3)
● some examples:
– :t max returns
max :: (Ord a) => a -> a -> a
– max 4 5 returns 5
– (max 4) 5 returns 5
– :t max 4 returns
max 4 :: (Num a, Ord a) => a -> a
– let foo = max 4
foo 5 returns 5
– :t max 4 5 returns
max 4 5 :: (Num a, Ord a) => a
10. Pointless Style
● let's say, we have the following function:
maxWithFour :: (Num a, Ord a) => a -> a
maxWithFour x = max 4 x
● what is the result of max 4 again?
:t max 4 returns max 4 :: (Num a, Ord a) => a -> a
● max 4 returns already a function which consumes a
parameter, so we can simplify our function:
maxWithFour :: (Num a, Ord a) => a -> a
maxWithFour = max 4
● but how can we achieve that with the following function?
fn x = ceiling (negate (tan (cos (max 50 x))))
11. Function Application (1)
● used with ($)
● has the following header:
:t ($)
($) :: (a -> b) -> a -> b
● compared with SPACE (normal function application)
– ($) has lowest priority
– ($) is right associative f $ g $ a b = (f (g (a b)))
– SPACE has highest priority
– SPACE is left associative f a b c = (((f a) b) c)
12. Function Application (2)
● what can we do with ($) ?
● helps us to avoid parentheses:
– instead of:
sum (map sqrt [1..20])
– we can write:
sum $ map sqrt [1..20]
● allows us also to wrap a value in a function:
map ($ 3) [(4+), (10*), (^2), sqrt]
returns
[7.0,30.0,9.0,1.7320508075688772]
13. Function Composition (1)
● Definition:
● used with (.)
● has the following header:
:t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c
● composing two functions produces a new function
● good for on-the-fly pass of a function to the next
function
14. Function Composition (2)
● what can we do with (.) ?
● helps us also to avoid parentheses
● → unwraps the parameter out of parentheses
– instead of:
map (xs -> negate (sum (tail xs))) [[1..5],
[3..6],[1..7]]
– we can write:
map (negate . sum . tail) [[1..5],[3..6],
[1..7]]
15. Composition vs. Application (1)
● IMPORTANT to know the difference between ($) and (.)
● best to compare both headers again:
– ($) :: (a -> b) -> a -> b
– (.) :: (b -> c) -> (a -> b) -> a -> c
● combination of both allows us parenthesis-less writing
● shorter code and mostly easier to read
● → possibility to write pointless-style functions with more
then one function call
16. Composition vs. Application (2)
● example with parameter:
– foo xs = sum (filter (> 10) (map (*2) xs))
– foo xs = sum $ filter (> 10) $ map (*2 ) xs
● example without parameter (pointless-style):
– foo xs = sum (filter (> 10) (map (*2) xs))
– foo = sum . filter (> 10) . map (*2)
17. Useful Types
● Maybe:
data Maybe a = Nothing | Just a
– contains maybe a type a or Nothing
– good for handling e.g. Hashmap lookup
● Nothing if key not exist, else Value of type a
● Either:
data Either a b = Left a | Right b
deriving (Eq, Ord, Read, Show)
– can contain type a or type b
– Left for e.g. Error Messages, Right for value
– like an extended Maybe with information for Nothing
18. Functor Typeclass (1)
class Functor f where
fmap :: (a -> b) -> f a -> f b
● for things that can be mapped over
● !!! Functor needs Types with 1 Typeparameter !!!
● fmap gets a function and a type and maps the function over
the type variable
● Instance for List:
– Remember: List has 1 Typeparameter [a], but is just
Syntactic Sugar for ([] a)
instance Functor [] where
fmap = map
– Example: fmap (*2) [2,3,4] returns [4,6,8]
19. Functor Typeclass (2)
class Functor f where
fmap :: (a -> b) -> f a -> f b
● Instance for Maybe
instance Functor Maybe where
fmap g (Just x) = Just (g x)
fmap g Nothing = Nothing
● Example:
– fmap (+3) Nothing returns Nothing
– fmap (+3) (Just 4) returns (Just 7)
20. Functor Typeclass (3)
class Functor f where
fmap :: (a -> b) -> f a -> f b
● Instance for Either
instance Functor (Either a) where
fmap f (Right x) = Right (f x)
fmap f (Left x) = Left x
● Either is a type with 2 Typeparameters!
● → we have to permanently include the first parameter in the
instance (curried function, partial application)
● → fmap do not change the 1st Typeparameter, only the 2nd
● → Left Type-Constructor of Either is often used for Error
Messages
21. Functor Typeclass (4)
class Functor f where
fmap :: (a -> b) -> f a -> f b
● Example:
– fmap (+3) (Left 4) returns (Left 4)
– fmap (+3) (Right 4) returns (Right 7)
● what happens, if we try to do that?
fmap (+) (Just 4)
● let's look at the type:
:t fmap (+) (Just 4)
fmap (+) (Just 4) :: Num a => Maybe (a -> a)
● partial application, BUT we can not use the Functor instance
on the result!
● → we need an extension → Applicative Functors
22. Sources
[1] Haskell-Tutorial: Learn you a Haskell (http://learnyouahaskell.com/,
2012/03/15)
[2] The Hugs User-Manual (
http://cvs.haskell.org/Hugs/pages/hugsman/index.html, 2012/03/15)
[3] The Haskellwiki (http://www.haskell.org/haskellwiki, 2012/03/15)