Reputation: 1203
I am a beginner of learning Haskell. Here is the problem I've encountered when using GHCi.
p :: Parser (Char, Char)
p = do x <- item
item
y <- item
return (x,y)
item :: Parser Char
item = P (\inp -> case inp of
[] -> []
(x:xs) -> [(x,xs)])
item is another parser where item :: Parser Char, simply item is to parse a string
When I load the file then execute
parse p "abcdef"
An execption is then shown:
*** Exception: You must implement (>>=)
Any idea for fixing such problem ?
Updated information:
The Parser is defined as follow:
newtype Parser a = P (String -> [(a,String)])
instance Monad Parser where
return :: a -> Parser a
return v = P (\inp -> [(v,inp)])
(>>=) :: Parser a -> (a -> Parser b) -> Parser b
p >>= f = --...
Upvotes: 1
Views: 266
Reputation: 89043
In order to use do
notation, your Parser
must be an instance of Monad
:
instance Monad Parser where
return :: a -> Parser a
return = -- ...
(>>=) :: Parser a -> (a -> Parser b) -> Parser b
p >>= f = -- ...
The compiler needs you to fill in definitions of return
and >>=
.
do
notation is syntatic sugar that desugars to use of >>=
(pronounced "bind"). For example, your code desugars to:
p :: Parser (Char, Char)
p = item >>= \x ->
item >>= \_ ->
item >>= \y ->
return (x,y)
Or, with more explicit parentheses:
p = item >>= (\x -> item >>= (\_ -> item >>= (\y -> return (x,y))))
>>=
describes how to combine a Parser a
along with a function a -> Parser b
to create a new Parser b
.
Using your definition of Parser
, a working Monad
instance is
instance Monad Parser where
return a = P $ \s -> [(a,s)]
p >>= f = P $ concatMap (\(a,s') -> runParser (f a) s') . runParser p
-- which is equivalent to
-- p >>= f = P $ \s -> [(b,s'') | (a,s') <- runParser p s, (b,s'') <- runParser (f a) s']
Consider what >>=
does in terms of a p :: Parser a
and a function f :: a -> Parser b
.
when unwrapped, p
takes a String
, and returns a list of (a,String)
pairs
runParser p :: String -> [(a,String)]
for each (a,String)
pair, we can run f
on the a
to get a new parser q
:
map go . runParser p :: String -> [(Parser b,String)]
where go :: (a, String) -> (Parser b, String)
go (a,s') = let q = f a in (q, s')
if we unwrap q
, we get a function that takes a String
and returns a list of (b, String)
pairs:
map go . runParser p :: String -> [(String -> [(b,String)],String)]
where go :: (a, String) -> (String -> [(b,String)],String)
go (a,s') = let q = f a in (runParser q, s')
we can run that function on the String
that was paired with the a
to get our list of `(b, String) pairs immediately:
map go . runParser p :: String -> [[(b,String)]]
where go :: (a, String) -> [(b,String)]
go (a,s') = let q = f a in runParser q s'
and if we flatten the list-of-lists that results we get an String -> [(b,String)]
, which is just unwrapped Parser b
concat . map go . runParser p :: String -> [(b,String)]
where go :: (a, String) -> [(b,String)]
go (a,s') = let q = f a in runParser q s'
Upvotes: 2