4

The code is as below:

type Parser a = String -> [(a, String)]

retrn :: a -> Parser a
retrn v = \inp -> [(v, inp)]

parse :: Parser a -> String -> [(a, String)]
parse p inp = p inp

item :: Parser Char
item = \inp -> case inp of
        []        -> []
        (x:xs)    -> [(x, xs)]

--problem code
p :: Parser (Char, Char)
p = do x <- item
       item
       y <- item
       retrn (x, y)

It gives the following type error:

SO-34035520.hs:19:8:
    Couldn't match type `[(Char, String)]' with `Char'
    Expected type: String -> [((Char, Char), String)]
      Actual type: Parser ([(Char, String)], [(Char, String)])
    In a stmt of a 'do' block: retrn (x, y)
    In the expression:
      do { x <- item;
           item;
           y <- item;
           retrn (x, y) }

What noteworthy is, the sample code that is on official website of the book can be interpreted smoothly, which is *.lhs format.

So, can somebody tell me why? I've been working on this struggle for days.

Thanks in advance.

Cactus
  • 27,075
  • 9
  • 69
  • 149
AhSeng Fan
  • 397
  • 5
  • 11
  • If the code in the literate haskell file works (which you should link, by the way) then it shouldn't be too much work to find your difference. Have you tried that? – Thomas M. DuBuisson Dec 02 '15 at 05:48

1 Answers1

9

(->) String has a Monad instance but it is not what you are looking for. When you use do-notation in the definition of p, this instance is the one that is picked up.

What you want to do is make your own Monad instance for Parser (this requires changing it from a type synonym to a newtype wrapper over String -> [(a, String)]) and then let that be picked up in the definition of p.

Note that your example code already has an implementation of return (under the name of retrn) which does the right thing, and it is also very different from what return for (->) String is (which would be retrn v = \inp -> v.

Community
  • 1
  • 1
Cactus
  • 27,075
  • 9
  • 69
  • 149