我是学习Haskell的初学者。这是我在使用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是另一个解析器,其中item :: Parser Char,只是item解析一个字符串
当我加载文件然后执行
parse p "abcdef"
然后显示一个execption:
*** Exception: You must implement (>>=)
是否有解决此类问题的想法?
更新信息:
Parser定义如下:
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 = --...
答案 0 :(得分:2)
要使用do
表示法,您的Parser
必须是Monad
的实例:
instance Monad Parser where
return :: a -> Parser a
return = -- ...
(>>=) :: Parser a -> (a -> Parser b) -> Parser b
p >>= f = -- ...
编译器需要您填写return
和>>=
的定义。
do
表示法是使用>>=
(发音为&#34; bind&#34;)的合成糖。例如,您的代码涉及:
p :: Parser (Char, Char)
p = item >>= \x ->
item >>= \_ ->
item >>= \y ->
return (x,y)
或者,更明确的括号:
p = item >>= (\x -> item >>= (\_ -> item >>= (\y -> return (x,y))))
>>=
介绍如何将Parser a
与函数a -> Parser b
结合使用以创建新的Parser b
。
使用Parser
的定义,一个有效的Monad
实例
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']
考虑>>=
对p :: Parser a
和函数f :: a -> Parser b
的影响。
解包时,p
需要String
,并返回(a,String)
对的列表
runParser p :: String -> [(a,String)]
对于每个(a,String)
对,我们可以在f
上运行a
以获得新的解析器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')
如果我们打开q
,我们会得到一个带String
的函数并返回(b, String)
对的列表:
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')
我们可以在与String
配对的a
上运行该功能,立即获取我们的`(b,String)对列表:
map go . runParser p :: String -> [[(b,String)]]
where go :: (a, String) -> [(b,String)]
go (a,s') = let q = f a in runParser q s'
如果我们将结果列表展平,我们会得到一个String -> [(b,String)]
,这只是打开的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'