我很難理解爲什麼這兩個片段在所謂的「窮人的嚴格分析」下產生不同的結果。數據和新類型之間的懶惰/嚴格
第一個例子使用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