Das Bedürfnis nach rein in Applikativen

19

Ich lerne Haskells Bewerber. Es scheint mir (ich liege wahrscheinlich falsch), dass diepure Funktion nicht wirklich benötigt wird, zum Beispiel:

pure (+) <*> [1,2,3] <*> [3,4,5]

kann geschrieben werden als

(+) <$> [1,2,3] <*> [3,4,5]

Kann jemand den Nutzen erklären, den die pureFunktion gegenüber der expliziten Zuordnung bietet fmap?

Gil Shafriri
quelle
1
Sie haben Recht - pure f <*> xist genau das gleiche wie fmap f x. Ich bin mir sicher, dass es einen Grund gibt, warum dies pureaufgenommen wurde Applicative, aber ich bin mir nicht ganz sicher, warum.
Bradn
4
Ich habe keine Zeit für eine Antwort und bin nicht davon überzeugt, dass dies ohnehin eine gute oder vollständige Antwort wäre, aber eine Beobachtung: pureermöglicht es einem, "reine" Werte in einer anwendbaren Berechnung zu verwenden. Während, wie Sie richtig beobachten, pure f <*> xdasselbe ist wie f <$> x, gibt es kein solches Äquivalent für beispielsweise f <*> x <*> pure y <*> z. (Zumindest glaube ich nicht.)
Robin Zigmond
3
Als eine andere, theoretischere Rechtfertigung - es gibt eine alternative Formulierung, die sie eng mit der wichtigen MonoidKlasse verknüpft -, die puredem MonoidIdentitätselement entspricht. (Dies deutet darauf hin, dass Applicativeohne pureinteressant sein könnte, da Semigroup- was ein ist, Monoidohne unbedingt eine Identität zu haben - immer noch verwendet wird. Eigentlich denke ich jetzt daran, dass PureScript genau eine solche pureKlasse "Applikativ ohne " hat, obwohl ich es nicht tue Ich weiß nicht, wofür es verwendet wird.)
Robin Zigmond
2
@ RobinZigmond fmap (\f' x' z' -> f' x' y z') f <*> x <*> z, denke ich. Die Idee ist in der ApplicativeDokumentation als Gesetz des "Austauschs".
HTNW
3
@RobinZigmond Applicativeohne pureexistiert wie Applyvon Semigroupoiden .
Duplode

Antworten:

8

Ich bin hier am Rande meiner Kompetenz, also nimm das nicht länger als es ist, aber es war ein bisschen zu lang für einen Kommentar.

Es mag praktische Gründe geben, purein die Typklasse aufgenommen zu werden, aber viele Haskell-Abstraktionen leiten sich aus theoretischen Grundlagen ab, und ich glaube, dass dies auch der Fall ist Applicative. Wie in der Dokumentation angegeben, handelt es sich um einen starken laxen monoidalen Funktor ( eine Erläuterung finden Sie unter https://cstheory.stackexchange.com/q/12412/56098 ). Ich nehme an, das puredient genau wie die Identitätreturn für Monad(was ein Monoid in der Kategorie der Endofunktoren ist ).

Erwägen pure und liftA2:

pure :: a -> f a
liftA2 :: (a -> b -> c) -> f a -> f b -> f c

Wenn Sie ein wenig blinzeln, können Sie sich vielleicht vorstellen, dass liftA2es sich um eine binäre Operation handelt. Dies steht auch in der Dokumentation:

Heben Sie eine Binärfunktion zu Aktionen auf.

pureist also die entsprechende Identität.

Mark Seemann
quelle
6
Genau. Applicativeohne purewäre ein, hm, halbgruppaler Funktor anstelle eines monoidalen.
Links um den
20

fmapschneidet es nicht immer. Insbesondere purekönnen Sie f(wo fist Applicative) vorstellen, wo Sie es noch nicht haben. Ein gutes Beispiel ist

sequence :: Applicative f => [f a] -> f [a]

Es nimmt eine Liste von "Aktionen", die Werte erzeugen, und verwandelt sie in eine Aktion, die eine Liste von Werten erzeugt. Was passiert, wenn die Liste keine Aktionen enthält? Das einzig vernünftige Ergebnis ist eine Aktion, die keine Werte erzeugt:

sequence [] = pure [] -- no way to express this with an fmap
-- for completeness
sequence ((:) x xs) = (:) <$> x <*> sequence xs

Wenn Sie dies nicht getan hätten pure, müssten Sie eine nicht leere Liste von Aktionen anfordern. Sie könnten es definitiv zum Laufen bringen, aber es ist, als würde man über Addition sprechen, ohne 0 zu erwähnen, oder Multiplikation ohne 1 (wie andere gesagt haben, weil Applicatives monoidal sind). Sie werden wiederholt auf Randfälle stoßen, die leicht zu lösen wären, pureaber stattdessen durch seltsame Einschränkungen Ihrer Eingaben und anderer Pflaster gelöst werden müssen.

HTNW
quelle