Der Benutzer ‚singpolyma‘ asked on reddit wenn es einige allgemeine Struktur zugrunde liegen:Kann ich eine Liste von Erfolgen mit Kurzschlussfehlern über die Zusammensetzung von Anwendungsfunktoren modellieren?
data FailList a e = Done | Next a (FailList a e) | Fail e
Ein freies Monade vorgeschlagen wurde, aber ich fragte mich, ob dies generell über applicative functors modelliert werden konnten. In Abstracting with Applicatives zeigt uns Bazerman, dass die Summe von zwei anwendungsbezogenen Funktoren auch ein anwendungsbezogener Funktor ist, mit einer Ausrichtung nach links/rechts, vorausgesetzt, wir haben eine natürliche Transformation in der Richtung der Verzerrung. Das klingt, als ob wir es brauchen! Also habe ich meinen Vorschlag gestartet, bin dann aber schnell auf Probleme gestoßen. Kann jemand Lösungen für diese Probleme ?:
Zum einen sehen wir mit der Definition der Summe zweier functors starten. Ich habe hier angefangen, weil wir Sum-Typen modellieren wollen - entweder Erfolge oder Erfolge und einen Misserfolg.
data Sum f g a = InL (f a) | InR (g a)
Und die beiden functors wir arbeiten wollen, sind:
data Success a = Success [a]
data Failure e a = Failure e [a]
Success
ist gerade nach vorne - es im Wesentlichen Const [a]
ist. Aber Failure e
bin ich nicht so sicher. Es ist kein anwendungsspezifischer Funktor, weil pure
keine Definition hat. Es ist jedoch eine Instanz von Apply:
instance Functor Success where
fmap f (Success a) = Success a
instance Functor (Failure e) where
fmap f (Failure e a) = Failure e a
instance Apply (Failure e) where
(Failure e a) <.> (Failure _ b) = Failure e a
instance Apply Success where
(Success a) <.> (Success b) = Success (a <> b)
instance Applicative Success where
pure = const (Success [])
a <*> b = a <.> b
Als nächstes wir die Summe dieser functors definieren können, mit einer natürlichen Transformation von rechts (so eine linke bias) nach links:
instance (Apply f, Apply g, Applicative g, Natural g f) => Applicative (Sum f g) where
pure x = InR $ pure x
(InL f) <*> (InL x) = InL (f <*> x)
(InR g) <*> (InR y) = InR (g <*> y)
(InL f) <*> (InR x) = InL (f <.> eta x)
(InR g) <*> (InL x) = InL (eta g <.> x)
Und das einzige, was wir jetzt tun müssen, ist unsere natürliche Transformation zu definieren, und hier kommt alles zusammen.
instance Natural Success (Failure e) where
eta (Success a) = Failure ???? a
Die Unfähigkeit, ein Failure
scheint zu sein, das Problem zu schaffen. Darüber hinaus ist sogar hacky und mit ⊥ ist keine Option, denn diese wird ausgewertet werden, wenn Sie InR (Success ...) <*> InL (Failure ...)
haben.
Ich fühle mich wie ich etwas vermisse, aber ich habe keine Ahnung, was es ist.
Kann dies getan werden?
Der Naturzustand 'forall (f :: a -> b). eta. fmap f == fmap f. Es wird dringend empfohlen, dass die Fehlerkomponente konstant sein muss. Das bringt mich dazu, ein 'Default e => Applicative (Fehler e)' schreiben zu wollen. –
Auch Ihre 'Apply' /' Applicative' Instanzen sind seltsam. Ich habe die Köpfe so fixiert, dass sie gut kontrollieren, aber sie werden auch nicht überprüft! 'Success a' ist nicht wirklich isomorph zu' Constant [a] 'though, though ... zumindest braucht es mehr Typenindizes! –
@tel - "Default" scheint möglich, ich kann einfach nicht sehen, was eine vernünftige "Standardfehlermeldung" wäre. Außerdem wurden Ihre Änderungen von anderen SO-Redakteuren abgelehnt, obwohl sie gültig sind. Ich werde sie selbst anwenden. – ocharles