1

I'm trying to write a simple Parser, so all the declarations are listed in the image below, but when I try to compile this module it fails. I'm following the tutorial provided by this source -> Haskell lessons suggested by official site and specifically this video by Dr. Erik Meijer (Lesson on Parser with "do" construct).

The problem is that I thought that the "do" construct was able to "concatenate" outputs from a previous function in a descending way, but the way that this p function should work seems to be magic to me. What's the right implementation?

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

-- A simple Parser that captures the first char of the string, puts it in
-- the first position of the couple and then puts the rest of the string into
-- the second place of the couple inside the singleton list.
item :: Parser Char
item = \inp -> case inp of
    [] -> []
(x:xs) -> [(x, xs)]

-- Simple parser that always fails.    
failure :: Parser a
failure = \inp -> []

-- Returns the type of the parser without operating on the input.
return1 :: a -> Parser a
return1 v = \inp -> [(v, inp)]

-- Explicit call to parse.
parse :: Parser a -> String -> [(a, String)]
parse p inp = p inp

-- Some kind of "or" operator that if the first parser fails (returning an empty list) it
-- parses the second parser.
(+++) :: Parser a -> Parser a -> Parser a
p +++ q = \inp -> case p inp of
    [] -> parse q inp
    [(v, out)] -> [(v, out)]

-- The function within I'm having troubles.
p :: Parser (Char,Char)
p = do
    x <- item
    item
    y <- item
    return1 (x, y)

enter image description here

This is how it's explained by Dr. Meijer:

And this is how it should work: enter image description here

6
  • 4
    Where is your Monad instance for Parser? Commented Oct 31, 2017 at 15:48
  • 4
    Your p is making use of the (->) String monad, not any kind of Parser monad. You need to make Parser a newtype, and then write the Monad instance for it before you can use do as you want. Commented Oct 31, 2017 at 16:30
  • @n.m. Sorry, I edited the question. Commented Oct 31, 2017 at 16:38
  • 5
    I can't understand why this is being downvoted. Images should be replaced, I concur -- but at least this question shows some effort, unlike many others by people who are learning Haskell. Commented Oct 31, 2017 at 17:29
  • 4
    I think Erik Meijer is playing fast and loose in his talk. You cannot really make Parser an instance of Monad in a way that makes monadic parsing work. The problem is, String -> is an instance of Monad (so the do notation works), but it's a wrong instance and produces all the wrong types.Try to rewrite this function using an explicit bind rather than do. Alternatively you can wrap Parser in a newtype like this newtype Parser a = Parser { unparser :: String -> [(a, String)] } and define a Monad instance for that... but that's probably too much for the first Monad lesson... Commented Oct 31, 2017 at 17:38

1 Answer 1

4

Your Parser is just a type synonym for a function. The friendly parsers you've seen in use are all proper types of their own, with Functor and Applicative instances, along with (in most cases) Alternative, Monad, and MonadPlus instances. You probably want something that looks like the following (untested, never compiled) version.

import Control.Monad (ap, liftM)
import Control.Applicative (Alternative (..))

newtype Parser a = Parser
  { runParser :: String -> [(a, String)] }

instance Functor Parser where
  fmap = liftM

instance Applicative Parser where
  pure v = Parser $ \inp -> [(v, inp)]
  (<*>) = ap

instance Monad Parser where
  -- The next line isn't required for
  -- recent GHC versions
  -- return = pure

  Parser m >>= f = Parser $ \s ->
    [(r, s'') | (x, s') <- m s
              , (r, s'') <- runParser (f r) s']

(+++) :: Parser a -> Parser a -> Parser a
p +++ q = Parser $ \inp -> case runParser p inp of
  [] -> runParser q inp
  [(v, out)] -> [(v, out)]

failure :: Parser a
failure = Parser $ \inp -> []

instance Alternative Parser where
  (<|>) = (+++)
  empty = failure

instance MonadPlus Parser
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.