yas*_*sar 1 monads haskell do-notation
我是haskell的新手,我正在尝试理解本文档中用于创建Monadic解析器的方法https://www.cs.nott.ac.uk/~gmh/pearl.pdf
我没有完全遵循它,而是试图以不同的方式做到这一点,以便正确理解它,因此,我最终得到了这段代码
newtype Parser a = Parser (String -> Maybe (a, String))
item :: Parser Char
item = Parser (\cs -> case cs of
"" -> Nothing
(c:cs) -> Just (c, cs))
getParser (Parser x) = x
instance Monad Parser where
return x = Parser (\cs -> Just (x,cs))
(Parser p) >>= f = Parser (\cs -> let result = p cs in
case result of
Nothing -> Nothing
Just (c,cs') -> getParser (f c) cs')
takeThreeDropSecond :: Parser (Char, Char)
takeThreeDropSecond = do
c1 <- item
item
c2 <- item
return (c1, c2)
Run Code Online (Sandbox Code Playgroud)
这似乎有效,但我很难跟踪记号中发生的事情.
例如; in c1 <- item,分配给c1什么?它是包含在Parser类型或计算结果中的函数,还是其他什么?另外,do notation中的第二行只是item,它只是运行item但不分配结果?最后,return (c1,c2)产生了什么?是Parser (String -> Maybe ((c1, c2)), String)或只是Just (c1, c2)?
该Parser类型包含一个函数,该函数可以1)表示使用的失败Maybe,2)返回未解析的剩余文本(a, String)以及3)a已解析的某个值,可以是任何值.monad实例是将它们绑在一起的管道.该return实现创建了Parser一个函数,1)成功的Just东西,2)不修改其输入文本,3)直接传递给它的值.该>>=实施需要一个解析器和功能,然后返回由先运行创造了一个新的解析器p,然后根据该结果是否通过或失败运行f.
在takeThreeDropSecond,首先c1 <- item说"解析给定的使用item,将其结果分配给c1,并向前馈送其余的输入".这不会在item解析器内部分配函数c1,它会item针对当前输入分配运行函数的结果.然后你到达item,使用解析一个值item,不将它分配给任何东西,并向前输入其余的输入.接下来你到达c2 <- item,它与第一行基本相同,最后return (c1, c2),它将扩展到Parser (\cs -> Just ((c1, c2), cs)).这意味着return (c1, c2)有类型Parser (Char, Char).使用类型注释即可
takeThreeDropSecond :: Parser (Char, Char)
takeThreeDropSecond = do
(c1 :: Char) <- (item :: Parser Char)
(item :: Parser Char)
(c2 :: Char) <- (item :: Parser Char)
(return (c1, c2) :: Parser (Char, Char))
Run Code Online (Sandbox Code Playgroud)
请注意,任何monadic do块的最后一行必须与它所属的函数具有相同的类型.因为return (c1, c2)有类型Parser (Char, Char),所以必须takeThreeDropSecond,反之亦然.