我很难理解为什么这两个片段在所谓的“穷人严格分析”下会产生不同的结果。
第一个示例使用data
(假设一个正确的 Applicative 实例):
data Parser t a = Parser {
getParser :: [t] -> Maybe ([t], a)
}
> getParser (pure (,) <*> literal ';' <*> undefined ) "abc"
*** Exception: Prelude.undefined
第二种用途newtype
。没有其他区别:
newtype Parser t a = Parser {
getParser :: [t] -> Maybe ([t], a)
}
> getParser (pure (,) <*> literal ';' <*> undefined ) "abc"
Nothing
literal x
是一个解析器,如果其参数与第一个标记匹配,则成功使用一个输入标记。所以在这个例子中,它失败了,因为;
不匹配a
。但是,该data
示例仍然看到下一个解析器未定义,而该newtype
示例没有。
我已经阅读了 this、this和this,但对它们的理解不够深入,无法理解为什么第一个示例未定义。在我看来,在这个例子中,newtype
比答案更懒惰data
,与答案所说的相反。(至少还有一个人也对此感到困惑)。
为什么切换 fromdata
会newtype
改变这个例子的定义?
这是我发现的另一件事:使用这个 Applicative 实例,data
上面的解析器输出未定义:
instance Applicative (Parser s) where
Parser f <*> Parser x = Parser h
where
h xs =
f xs >>= \(ys, f') ->
x ys >>= \(zs, x') ->
Just (zs, f' x')
pure a = Parser (\xs -> Just (xs, a))
而对于这个实例,data
上面的解析器不会输出 undefined (假设有一个正确的 Monad 实例Parser s
):
instance Applicative (Parser s) where
f <*> x =
f >>= \f' ->
x >>= \x' ->
pure (f' x')
pure = pure a = Parser (\xs -> Just (xs, a))
完整的代码片段:
import Control.Applicative
import Control.Monad (liftM)
data Parser t a = Parser {
getParser :: [t] -> Maybe ([t], a)
}
instance Functor (Parser s) where
fmap = liftM
instance Applicative (Parser s) where
Parser f <*> Parser x = Parser h
where
h xs = f xs >>= \(ys, f') ->
x ys >>= \(zs, x') ->
Just (zs, f' x')
pure = return
instance Monad (Parser s) where
Parser m >>= f = Parser h
where
h xs =
m xs >>= \(ys,y) ->
getParser (f y) ys
return a = Parser (\xs -> Just (xs, a))
literal :: Eq t => t -> Parser t t
literal x = Parser f
where
f (y:ys)
| x == y = Just (ys, x)
| otherwise = Nothing
f [] = Nothing