Search code examples
haskellfunctor

Haskell : understand Functor


I am doing an Haskell tutorial about Applicative Functor : CIS194: Homework10 - applicative

In the tutorial, the below parser is given:

-- A parser for a value of type a is a function which takes a String
-- representing the input to be parsed, and succeeds or fails; if it
-- succeeds, it returns the parsed value along with the remainder of
-- the input.
newtype Parser a = Parser { runParser :: String -> Maybe (a, String) }

On exercise 2, we are asked to implement an Applicative instance for Parser.
Before implementing Applicative, we need to implement Functor.
My Functor Parser implementation is :

instance Functor Parser where
  fmap f p = Parser ( -- take a function and a parser
    \s0 -> case runParser p s0 of -- parse a string
        Nothing -> Nothing -- if parse fails, returns nothing
        Just (a,s1) -> Just (f a,s1) -- if parse succeed, returns
                                      --1. 1st function applied to parsed result
                                      --2. remaining string
    )

However i found anoter way to implement this Functor : bschwb /cis194-solutions
The Functor Parser implementation is :

first :: (a -> b) -> (a, c) -> (b, c)
first f (a, c) = (f a, c)

instance Functor Parser where
  fmap f (Parser rp) = Parser (fmap (first f) . rp)

I do not understand the '. rp' part, can you please help me ?
To my understanding :

  • Parser rp : 'rp' can be anything (Integer, tuple, function ...) and we are not supposed to know what it is;
  • The '.' operator applies only to functions;
  • So we can not mix '.' and 'rp' because we are not sure 'rp' will be a function. What did I miss or misunderstand ?

Thank you for your help.


Solution

  • In newtype Parser a = Parser { runParser :: String -> Maybe (a, String) }, I was focusing on the data type Parser a, and not on the constructor Parser :: (String -> Maybe (a, String)) -> Parser a.

    Now this is clear:

    instance Functor Parser where
        fmap -- Functor f => (a->b) -> f a -> f b
          func -- a -> b
          (Parser rp) -- regarding Parser constructor rp :: String -> Maybe (a, String)
         = Parser
          (
            fmap (first func) -- we can deduce : fmap (first func) :: Functor f => f (a, c) -> f (func a, c)
            . -- and we know : (.) :: (b -> c) -> (a -> b) -> (a -> c)
            rp -- rp :: String -> Maybe (a, String)
          ) -- therefore : fmap (first func).rp :: String -> Maybe (func a, String)
    

    Thanks duplode for his comment.