我很难理解为什么这两个片段在所谓的“穷人的严格分析”下产生不同的结果。数据和新类型之间的懒惰/严格
第一个例子使用data
(假设正确的应用型实例):
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
,这与答案所说的相反。 (至少one other person也被这个困惑了)。
为什么从data
切换到newtype
改变了这个例子的定义?
这是我发现的另一件事情:使用此应用型情况下,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
解析器上面并不输出不确定的(假设一个正确的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
当提出这样的问题时,如果包含所有相关的代码,如果它足够小以适合(这包括'Functor'和'Monad'实例,'literal''),那么通常会更好,这样人们就不会您不必猜测您是如何编写函数的(正如您已经指出的那样,即使很小的变化也会影响行为)。 – shachaf
@shachaf这里真正的问题不是“我该如何解决我的代码?” - 我已经这样做了 - 但“数据”和“新类型”在严格性/懒惰方面有什么不同?“对不起,如果这不是从问题中清楚。 –
是的,但即便如此,我们如何解释代码的情况,而不知道代码是什么样的? – shachaf