简介
我正在尝试了解这个东西:
satisfy :: (Char -> Bool) -> Parser Char
satisfy pred = PsrOf p
where
p (c:cs) | pred c = Just (cs, c)
p _ = Nothing
等价于这个:
satisfy :: (Char -> Bool) -> Parser Char
satisfy pred = do
c <- anyChar
if pred c then return c else empty
背景
以下是有关Haskell解析的一些讲座笔记片段,我正在努力理解:
import Control.Applicative
import Data.Char
import Data.Functor
import Data.List
newtype Parser a = PsrOf (String -> Maybe (String, a))
-- Function from input string to:
--
-- * Nothing, if failure (syntax error);
-- * Just (unconsumed input, answer), if success.
dePsr :: Parser a -> String -> Maybe (String, a)
dePsr (PsrOf p) = p
-- Monadic Parsing in Haskell uses [] instead of Maybe to support ambiguous
-- grammars and multiple answers.
-- | Use a parser on an input string.
runParser :: Parser a -> String -> Maybe a
runParser (PsrOf p) inp = case p inp of
Nothing -> Nothing
Just (_, a) -> Just a
-- OR: fmap (\(_,a) -> a) (p inp)
-- | Read a character and return. Failure if input is empty.
anyChar :: Parser Char
anyChar = PsrOf p
where
p "" = Nothing
p (c:cs) = Just (cs, c)
-- | Read a character and check against the given character.
char :: Char -> Parser Char
-- char wanted = PsrOf p
-- where
-- p (c:cs) | c == wanted = Just (cs, c)
-- p _ = Nothing
char wanted = satisfy (\c -> c == wanted) -- (== wanted)
-- | Read a character and check against the given predicate.
satisfy :: (Char -> Bool) -> Parser Char
satisfy pred = PsrOf p
where
p (c:cs) | pred c = Just (cs, c)
p _ = Nothing
-- Could also be:
-- satisfy pred = do
-- c <- anyChar
-- if pred c then return c else empty
instance Monad Parser where
-- return :: a -> Parser a
return = pure
-- (>>=) :: Parser a -> (a -> Parser b) -> Parser b
PsrOf p1 >>= k = PsrOf q
where
q inp = case p1 inp of
Nothing -> Nothing
Just (rest, a) -> dePsr (k a) rest
我理解了Monad定义的所有部分,具体地说,我不明白以下行如何返回类型为Parser b
的内容,正是这种类型被(>>=)
定义所需:
Just (rest, a) -> dePsr (k a) rest
如果没有例子的话,我很难理解“Monad定义”的含义。谢天谢地,在satisfy
函数的备用版本中,我们有一个例子可以使用do-notation (当然意味着会调用Monad)。我还不太理解do-notation,所以这里是satisfy
的desugared版本:
satisfy pred = do
anyChar >>= (c ->
if pred c then return c else empty)
基于我们的(>>=)
定义的第一行,即
PsrOf p1 >>= k = PsrOf q
我们将
anyChar
作为我们的PsrOf p1
,将(c -> if pred c then return c else empty)
作为我们的k
。我不明白的是,在dePsr (k a) rest
中,(k a)
如何返回一个Parser
(至少应该返回),否则调用它上面的dePsr
就没有意义了。而且有rest
存在更加令人困惑。即使(k a)
返回一个Parser
,调用dePsr
也会从返回的Parser
中提取基础函数,并将rest
作为输入传递给它。这显然不会像(>>=)
的定义所要求的那样返回Parser b
类型的值。显然我在某个地方误解了一些东西。
dePsr(k a) rest
函数位于q
函数内部。q
函数不是直接由... >>= ...
返回的结果。... >>= ...
的结果是PsrOf q
,而不是q
。 - David Youngk
的类型为a -> Parser b
(可以在注释的类型签名中看到)。因此,如果您给k
一个a
值,它将会给您一个Parser b
值。这就是为什么k a :: Parser b
。 - David Young