いわゆる「貧乏人の正格性解析」の下で、これら2つのスニペットが異なる結果を生成する理由を理解するのに苦労しています。
最初の例ではdata
、(正しいApplicativeインスタンスを想定して)次を使用します。
data Parser t a = Parser {
getParser :: [t] -> Maybe ([t], a)
}
> getParser (pure (,) <*> literal ';' <*> undefined ) "abc"
*** Exception: Prelude.undefined
2番目はを使用しnewtype
ます。他に違いはありません:
newtype Parser t a = Parser {
getParser :: [t] -> Maybe ([t], a)
}
> getParser (pure (,) <*> literal ';' <*> undefined ) "abc"
Nothing
literal x
引数が最初のトークンと一致する場合、入力の1つのトークンの消費に成功するパーサーです。したがって、この例では、;
が一致しないため失敗しますa
。ただし、このdata
例では、次のパーサーが未定義であることがわかりますが、newtype
例では定義されていません。
私はこれ、これ、そしてこれを読みましたが、最初の例が未定義である理由を理解するのに十分にそれらを理解していません。この例でnewtype
は、答えが言ったこととは反対に、より怠惰であるように私には思えます。data
(少なくとも1人の他の人もこれに混乱しています)。
この例の定義data
を変更するためにから切り替えるのはなぜですか?newtype
私が発見したもう1つのことは、この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
上記のパーサーは未定義を出力しません(の正しいモナドインスタンスを想定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