Download - 08. haskell Functions
Functions
Sebastian Rettig
Every function in haskell consumes exactly one parameter and returns a value.
Every function in haskell consumes exactly one parameter and returns a value.
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)
Haskell Features
● Pure Functional Programming Language● Lazy Evaluation ● Pattern Matching and Guards● List Comprehension● Type Polymorphism
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'])
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]
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?
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
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
Curried Functions (4)● we can also partial apply infix functions
(/10) 2 returns 0.2
(10/) 2 returns 5
(++ “bar”) “foo” returns “foobar”
(“bar” ++) “foo” returns “barfoo”
:t (`elem` ['a'..'z'])(`elem` ['a'..'z']) :: Char -> Bool
:t ('a' `elem`)
(`elem` ['a'..'z']) :: [Char] -> Bool
:t elem
elem :: Eq a => a -> [a] -> Bool
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))))
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)
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]
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
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]]
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
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)
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
Functor Typeclass (1)class Functor f wherefmap :: (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 [] wherefmap = map
– Example: fmap (*2) [2,3,4] returns [4,6,8]
Functor Typeclass (2)class Functor f wherefmap :: (a -> b) -> f a -> f b
● Instance for Maybe
instance Functor Maybe wherefmap g (Just x) = Just (g x) fmap g Nothing = Nothing
● Example:
– fmap (+3) Nothing returns Nothing
– fmap (+3) (Just 4) returns (Just 7)
Functor Typeclass (3)class Functor f wherefmap :: (a -> b) -> f a -> f b
● Instance for Either
instance Functor (Either a) wherefmap 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
Functor Typeclass (4)class Functor f wherefmap :: (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
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)