Applicative functors, Part I
Posted on 2015-08-23 19:40:32 +0900 in Functional Programming
Lecture Contents
The induction from Functor
to Applicative
is quite beautiful.
Recalled that there exists fmap :: (a -> b) -> (f a -> f b)
in Functor
, it would be great if this mapping
function is still valid if the input consists of more than one variable, namely (a -> b -> c) -> (f a -> f b -> f c)
We have
h :: a -> b -> c
fa :: f a
fb :: f b
fc :: f c
Use fmap
to lift functions,
h :: a -> (b -> c)
fmap h :: f a -> f (b -> c)
fmap h fa :: f (b -> c)
But there is no way to make
f (b -> c) -> fb -> fc
Applicative
has the (<*>)
to implement it, namely
(<*>) :: f (a -> b) -> f a -> f b
The final induction is
liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
liftA2 = h <$> fa <*> fb
Home Work
Exercise 1
-- Ex. 1 - implement a Functor instance for Parser
--
-- You may find it useful to implement:
-- first :: (a -> b) -> (a,c) -> (b,c)
first :: (a -> b) -> (a, c) -> (b, c)
first f (x, y) = (f x, y)
instance Functor Parser where
fmap f parser = Parser $ \s -> first f <$> runParser parser s
Exercise 2
-- Ex. 2 - implement an Applicative instance for Parser
--
instance Applicative Parser where
pure a = Parser (\s -> Just (a, s))
p1 <*> p2 = Parser parse
where parse s = do
r1 <- runParser p1 s
r2 <- runParser p2 (snd r1)
return (fst r1 $ fst r2, snd r2)
Exercise 3
-- Ex. 3a - Create a parser:
--
-- abParser :: Parser (Char, Char)
--
-- which expects to see the characters ’a’ and ’b’ and returns them as a pair
abParser :: Parser (Char, Char)
abParser = (,) <$> char 'a' <*> char 'b'
-- Ex. 3b - Create a parser:
--
-- abParser_ :: Parser ()
--
-- which acts in the same way as abParser but returns () instead of 'a' and 'b'
abParser_ :: Parser ()
abParser_ = const . const () <$> char 'a' <*> char 'b'
-- Ex. 3c - Create a parser:
--
-- intPair
--
-- which reads two integer values separated by a space and returns the integer
-- values in a list. You should use the provided posInt to parse the integer values.
intPair :: Parser [Integer]
intPair = (\x y -> [x, y]) <$> posInt <* char ' ' <*> posInt
Exercise 4
instance Alternative Parser where
empty = Parser $ const Nothing
Parser p1 <|> Parser p2 = Parser $ liftA2 (<|>) p1 p2
Exercise 5
-- Ex. 5 - Implement a parser:
--
-- intOrUppercase :: Parser ()
--
-- which parses either an integer value or an uppercase character, and fails otherwise.
intOrUppercase :: Parser ()
intOrUppercase = const () <$> posInt <|> const () <$> satisfy isUpper
Hide Comments
comments powered by Disqus