Applicative functors, Part I

Posted on 2015-08-23 19:40:32 +0900 in Functional Programming Haskell CIS194

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
----------------------------------- 本文内容遵从CC版权协议转载请注明出自kamelzcs -----------------------------------
«  | IO »

Hide Comments

comments powered by Disqus