1. Context
Sebastian Rettig
An applicative value can be seen as aa value with
An applicative value can be seen as value with
an added context. - - A fancy value.
an added context. A fancy 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. Nice to remember (3)
Curried Function:
● every function in haskell consumes exactly one
parameter and returns a value
● PARTIAL APPLICATION
● 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)
7. Nice to remember (4)
Pointless Style:
● based on partial Application → simpler code
maxWithFour x = max 4 x
is the same as
maxWithFour = max 4
● use Function Application ($) to avoid Parenthesis on
function call with parameters
sqrt $ 3 + 4 + 9
● use Function Composition (.) to avoid Parenthesis on
chaining functions
fn = ceiling . negate . tan . cos . max 50
8. Type Refresher (1)
create a Type:
● data MyVector = Nirvana
| Single Int
| Tuple Int Int
| Triple Int Int Int
●
MyVector is the Type
●
Nirvana, Single, Tuple, Triple are Type Constructors
● Type Constructors are normal functions
:t Single is Single :: Int -> MyVector
● Type Constructors can have Parameters (values)
Single, Tuple, Triple have 1, 2 and 3
9. Type Refresher (2)
create a Type with Record Syntax:
● data MyVector2 = Nirvana2
| Single2 {x :: Int}
| Tuple2 {x :: Int, y :: Int}
| Triple2 {x :: Int, y :: Int, z :: Int}
● Nirvana2, Single2, Tuple2, Triple2 are Type Constructors
● x, y, z are selectors
functions who lookup specific fields in the data type → like GET
functions
:t x is x :: MyVector2 -> Int
● e.g.: foo = Single2 {x=4}
x foo returns 4
:t foo returns foo :: MyVector2
10. Type Refresher (3)
to make the Type more generic:
● data MyVector3 a = Nirvana3
| Single3 {x' :: a}
| Tuple3 {x' :: a, y' :: a}
| Triple3 {x' :: a, y' :: a, z' :: a}
●
a is type parameter and selector x' has the following header
:t x' is x' :: MyVector3 a -> a
● if we want to use this type, we have to set the Type parameter
OR let Haskell detect the Type parameter
● e.g.: foo = Single3 {x'=4}
:t foo returns foo :: MyVector3 Integer
● e.g.: foo = Nirvana3
:t foo returns foo :: MyVector3 a
11. Type Refresher (4)
a Type can have more than one Type parameter:
● data MyVector4 a b c = Nirvana4
| Single4 {x'' :: a}
| Tuple4 {x'' :: a, y :: b}
| Triple4 {x'' :: a, y'' :: b, z'' :: c}
●
a, b, c are type parameter, selector x has header
:t x'' is x'' :: MyVector4 a b c -> a
● e.g.: foo = Single4 {x''=4}
:t foo returns foo :: MyVector4 Integer b c
● e.g.: foo = Nirvana4
:t foo returns foo :: MyVector4 a b c
● → Partial Application!
12. Kind
● explains the steps which are necessary to evaluate the data
from that type
● → evaluate = the type is fully applied
● can be used to find how much parameters a type has
● GHCi- Command :k
● :k MyVector returns MyVector :: *
● :k MyVector2 returns MyVector2 :: *
● :k MyVector3 returns MyVector3 :: * -> *
● :k MyVector4 returns MyVector4 :: * -> * -> * -> *
● :k MyVector3 Int returns MyVector3 Int :: *
● :k MyVector4 Int Int returns MyVector4 Int Int :: * -> *
13. Useful Types
● Maybe:
data Maybe a = Nothing | Just a
– for operations, which can fail
– contains data of type a (Just a) or Nothing
– good for handling e.g. Hashmap lookup
● 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
– BUT why is Error Message the first parameter?
14. Implement Membership (1)
● Let's refresh again how to implement a Typeclass-
Membership:
● first the definition of Typeclass Eq:
:i Eq
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
-- Defined in GHC.Classes
● What is a ? → a is used by (==) and (/=) as parameter
● → needs to be a fully applied type (concrete type)
● → :k must return *
15. Implement Membership (2)
● But how can we make MyVector3 a member of Eq ?
● → we have to make MyVector3 fully applied type, e.g.:
instance Eq (MyVector3 Int) where
Nirvana3 == Nirvana3 = True
Single3 {x'=x1} == Single3 {x'=x2} = (x1 == x2)
...
● Or with using generic Type Parameter:
instance Eq (MyVector3 a) where
Nirvana3 == Nirvana3 = True
Single3 {x'=x1} == Single3 {x'=x2} = (x1 == x2)
...
● do a has Type-Class restrictions? If yes, which?
16. Implement Membership (3)
● And what about that?
instance Eq MyVector3 where
Nirvana3 == Nirvana = True
Single3 {x'=x1} == Single {x'=x2} = (x1 == x2)
...
● Is this membership correct?
17. 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 kind * -> * !!!
● fmap gets a function and a type and maps the function
over the type variable → the type variable can change!
● Instance for List:
instance Functor [] where
fmap = map
– Example: fmap (*2) [2,3,4] returns [4,6,8]
18. 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)
– fmap (show) (Just 4) returns (Just “4”)
19. 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 kind * -> * -> * !
● → we have to permanently include the first parameter in the
instance (partial application)
● → fmap only maps over the second Type-Parameter!
● → Left Type-Constructor is often used for Error Messages
20. 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 Just (4+)
● → we need an extension → Applicative Functors
21. Lifting a Function
● if we partial apply fmap, the header has the following structure
:t fmap (*2) results in
fmap (*2) :: (Num a, Functor f) => f a -> f a
:t fmap (cycle 3) results in
fmap (cycle 3) :: (Functor f) => f a -> f [a]
● → this is called lifting a function
● → we can predefine a normal function which gets a Functor
and returns a Functor
● → we move the function inside the Type and operate on type
variables
● → we lift the function up to the type → normal function can
work with complex types
22. Applicative Functor (1)
class (Functor f) => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
● pure is a function who wraps a normal value into applicative
– creates a minimal context
● (<*>) takes a functor with a function in it and another functor
– extracts that function from the first functor
– and then maps it over the second one
23. Applicative Functor (2)
class (Functor f) => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
● Instance for Maybe
instance Applicative Maybe where
pure = Just
Nothing <*> _ = Nothing
(Just f) <*> something = fmap f something
● Example:
– Just (+3) <*> Just 9 returns Just 12
– pure (+3) <*> Just 10 returns Just 13
– Just (++"hah") <*> Nothing returns Nothing
24. Applicative Functor (3)
class (Functor f) => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
● Instance for []
instance Applicative [] where
pure x = [x]
fs <*> xs = [f x | f <- fs, x <- xs]
● Example:
– [(*0),(+100),(^2)] <*> [1,2,3]
returns [0,0,0,101,102,103,1,4,9]
– pure "Hey" :: [String] returns ["Hey"]
– [(+),(*)] <*> [1,2] <*> [3,4]
returns [4,5,5,6,3,4,6,8]
25. Applicative Functor (4)
● pure f <*> x equals fmap f x
● → in Control.Applicative exists a specific function
(<$>) :: (Functor f) => (a -> b) -> f a -> f b
f <$> x = fmap f x
● So we can do the same much prettier:
(++) <$> Just "johntra" <*> Just "volta"
returns Just "johntravolta"
(++) <$> ["ha","heh","hmm"] <*> ["?","!","."]
returns ["ha?", "ha!", "ha.", "heh?", "heh!",
"heh.", "hmm?", "hmm!", "hmm."]
26. Applicative Functor (5)
class (Functor f) => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
● Instance for IO
instance Applicative IO where
pure = return
a <*> b = do
f <- a
x <- b
return (f x)
27. Applicative Functor (6)
Example for IO:
● instead of writing this:
myAction :: IO String
myAction = do
a <- getLine
b <- getLine
return $ a ++ b
● we can write this:
myAction :: IO String
myAction = (++) <$> getLine <*> getLine
28. Applicative Context
● Applicative Types can bee seen as Types with context:
– Maybe, Either for things which can fail
– [ ] as non-deterministic result
– IO as values send or get from outside
● Applicative functors allows us to operate in applicative types
like normal types and provide the context!
● → We don't need to pattern match against the Context in
every operation we use in our functions!
29. Lifting a Function (Applicative)
● Function lifting in for Applicative:
liftA :: Applicative f => (a -> b) -> f a -> f b
– same as fmap
– fmap :: Functor f => (a -> b) -> f a -> f b
liftA2 :: (Applicative f) => (a -> b -> c) -> f a
-> f b -> f c
liftA2 f a b = f <$> a <*> b
– gets a function, with 2 parameters
– operates on 2 Applicatives
– result is also an Applicative
30. 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)