Ich habe zu kämpfen, um zu verstehen, warum diese zwei Schnipsel unterschiedliche Ergebnisse unter der sogenannten "Strenge Analyse des armen Mannes" produzieren.Faulheit/Strenge zwischen Daten und newtype
Das erste Beispiel verwendet data
(eine korrekte Instanz Applicative vorausgesetzt):
data Parser t a = Parser {
getParser :: [t] -> Maybe ([t], a)
}
> getParser (pure (,) <*> literal ';' <*> undefined) "abc"
*** Exception: Prelude.undefined
Die zweite verwendet newtype
. Es gibt keinen anderen Unterschied:
newtype Parser t a = Parser {
getParser :: [t] -> Maybe ([t], a)
}
> getParser (pure (,) <*> literal ';' <*> undefined) "abc"
Nothing
literal x
einen Parser ist das ein Zeichen des Eingangs gelingt es raubend, wenn sein Argument mit dem ersten Token übereinstimmt. In diesem Beispiel schlägt es fehl, da ;
nicht mit a
übereinstimmt. Das data
Beispiel sieht jedoch immer noch, dass der nächste Parser nicht definiert ist, während das newtype
Beispiel nicht funktioniert.
Ich habe gelesen this, this und this, aber verstehe sie nicht gut genug, um zu bekommen, warum das erste Beispiel nicht definiert ist. Es scheint mir, dass in diesem Beispiel newtype
ist mehr faul als data
, das Gegenteil von dem, was die Antworten sagten. (Mindestens one other person wurde auch dadurch verwirrt).
Warum ändert sich die Definition dieses Beispiels von data
zu newtype
?
Hier ist eine andere Sache, die ich entdeckt: mit diesem Applicative Beispiel die data
Parser über Ausgänge undefined:
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))
während bei diesem Fall der data
Parser oben tut nicht Ausgang undefiniert (unter der Annahme, eine korrekte Monad-Instanz für Parser s
):
instance Applicative (Parser s) where
f <*> x =
f >>= \f' ->
x >>= \x' ->
pure (f' x')
pure = pure a = Parser (\xs -> Just (xs, a))
Voll Code-Schnipsel:
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
Wenn eine Frage wie diese zu fragen, ist es im Allgemeinen besser, wenn Sie alle relevanten Codes, wenn es klein genug ist, zu passen (dazu gehört auch die '' Functor' und Monad' Instanzen und 'literal'), so dass die Menschen don Sie müssen nicht genau abschätzen, wie Sie die Funktionen geschrieben haben (wie Sie bereits erwähnt haben, können auch kleine Änderungen das Verhalten beeinflussen). – shachaf
@shachaf die echte Frage hier ist nicht "Wie repariere ich meinen Code?" - Das habe ich schon gemacht - aber "was ist anders in Bezug auf Strenge/Faulheit zwischen" Daten "und" Newtype "?" Entschuldigung, wenn das aus der Frage nicht klar ist. –
Ja, aber wie können wir Ihnen erklären, was mit Ihrem Code passiert ist, ohne zu wissen, wie der Code aussieht? – shachaf