Ich denke, Sie haben bereits alle interessanten Möglichkeiten ausgeschöpft. Jede Monad m => m a -> m a
Funktion, die wir definieren könnten, sieht unweigerlich so aus:
e :: forall m a. Monad m => m a -> m a
e u = u >>= k
where
k :: a -> m a
k = _
Insbesondere wenn k = return
, e = id
. Damit dies e
nicht der Fall ist id
, k
muss es nicht u
trivial verwendet werden (z. B. k = const u
und entspricht k = flip fmap u . const
Ihren beiden Versuchen). In einem solchen Fall werden die u
Effekte jedoch dupliziert, was e
dazu führt , dass es sich bei einer Reihe von Monadenoptionen nicht um einen Monadenmorphismus handelt m
. Unter diesen Umständen ist der einzige vollständig polymorphe Monadenmorphismus in der Monadeid
.
Lassen Sie uns das Argument deutlicher machen.
Der Klarheit halber werde ich für einen Moment zur join
/ return
/ fmap
Präsentation wechseln . Wir wollen implementieren:
e :: forall m a. Monad m => m a -> m a
e u = _
Womit können wir die rechte Seite füllen? Die naheliegendste Wahl ist u
. An sich bedeutet das e = id
, was nicht interessant aussieht. Da wir jedoch auch haben join
, return
und fmap
es besteht die Möglichkeit , induktiv Argumentation, mit u
als Basisfall. Nehmen wir an v :: m a
, wir haben einige , die mit den Mitteln gebaut wurden, die wir zur Hand haben. Neben v
sich haben wir folgende Möglichkeiten:
join (return v)
, was v
uns nichts Neues sagt und daher auch nichts Neues sagt;
join (fmap return v)
, was auch ist v
; und
join (fmap (\x -> fmap (f x) w) v)
für einige andere, w :: m a
die nach unseren Regeln gebaut wurden, und einige f :: a -> a -> a
. (Das Hinzufügen von m
Ebenen zu der Art von f
, wie in a -> a -> m a
und zusätzlichen join
s, um sie zu entfernen, würde nirgendwohin führen, da wir dann die Herkunft dieser Ebenen nachweisen müssten, und die Dinge würden sich letztendlich auf die anderen Fälle reduzieren.)
Der einzig interessante Fall ist # 3. An dieser Stelle werde ich eine Abkürzung nehmen:
join (fmap (\x -> fmap (f x) w) v)
= v >>= \x -> fmap (f x) w
= f <$> v <*> w
Jede nicht u
rechte Seite kann daher in der Form ausgedrückt werden f <$> v <*> w
, wobei v
und w
entweder eine u
oder mehrere Iterationen dieses Musters sind und schließlich u
s an den Blättern erreichen. Anwendbare Ausdrücke dieser Art haben jedoch eine kanonische Form, die durch Verwendung der anwendbaren Gesetze erhalten wird, um alle Verwendungen von (<*>)
links neu zuzuordnen , was in diesem Fall so aussehen muss ...
c <$> u <*> ... <*> u
... wobei die Ellipse für null oder mehr weitere Vorkommen von u
getrennt <*>
steht und c
eine a -> ... -> a -> a
Funktion angemessener Arität ist. Da a
es vollständig polymorph ist, c
muss es aufgrund seiner Parametrizität eine const
ähnliche Funktion sein, die eines seiner Argumente auswählt. Unter diesen Umständen kann jeder solche Ausdruck in Bezug auf (<*)
und (*>)
...
u *> ... <* u
... wobei die Ellipse für null oder mehr weitere Vorkommen von u
getrennt durch entweder *>
oder steht <*
, da *>
rechts von a kein Nein steht <*
.
Zurück zum Start: Alle id
Implementierungen , die keine Kandidaten sind, müssen folgendermaßen aussehen:
e u = u *> ... <* u
Wir wollen e
auch ein Monadenmorphismus sein. Infolgedessen muss es sich auch um einen anwendbaren Morphismus handeln. Bestimmtes:
-- (*>) = (>>) = \u v -> u >>= \_ -> v
e (u *> v) = e u *> e v
Das ist:
(u *> v) *> ... <* (u >* v) = (u *> ... <* u) *> (v *> ... <* v)
Wir haben jetzt einen klaren Weg zu einem Gegenbeispiel. Wenn wir die anwendbaren Gesetze verwenden, um beide Seiten in die kanonische Form umzuwandeln, werden wir (noch) verschachtelte u
s und v
s auf der linken Seite und alle v
s nach allen u
s auf der rechten Seite haben. Das bedeutet, dass das Anwesen nicht für Monaden wie geeignet istIO
, State
oder Writer
, unabhängig davon , wie viele (*>)
und (<*)
es gibt in e
, oder genau , welche Werte werden von den aufgenommenen const
-ähnliche Funktionen auf beiden Seiten. Eine kurze Demo:
GHCi> e u = u *> u <* u -- Canonical form: const const <$> u <*> u <*> u
GHCi> e (print 1 *> print 2)
1
2
1
2
1
2
GHCi> e (print 1) *> e (print 2)
1
1
1
2
2
2
u
werden zwangsläufig , es sei denn duplizierte = id
? (Wir könnten auch schreibene u = do _ <- u; _ <- u; _ <- u; u
weitereu
Effekte und kombinieren .) Wie können wir mathematisch beschreiben, dass "ein monadischer Wertp :: m a
mehrere Effekte hat, von denen kopiert wurdeu :: m a
? Und wie können wir dann beweisen, dass doppelte (dreifache usw.)u
Effekte notwendigerweise zu Verstößen gegen führen."e u
, nämlich einen Ausdruck desu *> ... <* u
von Ihnen beschriebenen Formulars zu verwenden? Warum können wir keine andere clevere und komplizierte Kombination finden?fmap
,return
undjoin
, so dass wir etwas anderes bekommen? Es ist auch ein guter Schritt, anwendbare Morphismen zu berücksichtigen. Es könnte einfacher sein, die analoge Eigenschaft für anwendbare Morphismen zu beweisen als für Monadenmorphismen. (Die einzigen anwendungsbezogenen Morphismen, die anwendungsmäßig natürlich sind, sind Identitätsmorphismen?)join _
kann zu einem Nicht-id
Ergebnis führen, und # 3 ist der einzige Weg, der nicht zu einemid
unendlichen Rückschritt führt. (2) EinApplicative
: Informell, wenn Ihr einziger Kleisli-Pfeil istreturn
, verbrauchen Sie nicht die zusätzliche KraftMonad
, die Sie mitbringen, also können Sie genauso gut damit arbeitenApplicative
. (3) Ja, die analoge Eigenschaft gilt für anwendbare Morphismen. Der Teil meiner Argumentation, der mit der in sich geschlossenen kanonischen Form beginnt, sollte als Beweis ausreichen.