使用GHCi的Haskell中的Functional Parser示例

时间:2014-12-07 11:19:57

标签: haskell

我是学习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     = --...

1 个答案:

答案 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'