3 Stimmen

Warum ist die List-Monad-Methode für `>>` nicht als `flip const` definiert?

Gibt es einen bestimmten Grund, warum das Prelude das List-Monad nicht so definiert? (Beachten Sie die nicht standardmäßige Implementierung von >>.)

instance  Monad []  where
    m >>= k          = concat (map k m)
    m >> k           = k                 -- a.k.a. flip const
    return x         = [x]
    fail s           = []

Ich habe versucht, dies anhand der Monaden-Gesetze zu überprüfen, aber sie erwähnen >> nicht. Die Definition der Monad-Klasse ist folgende:

m >> k = m >>= \_ -> k

was in der []-Instanz zu folgendem übersetzt würde:

concat (map (\_ -> k) m)

was natürlich nicht gleich flip const ist - sie erzeugen offensichtlich unterschiedliche Ergebnisse für z.B. [1..5] >> return 1. Aber es ist für mich nicht klar, ob diese Standarddefinition ein Gesetz ist, das Instanzen von Monad beachten müssen, oder einfach eine Standardimplementierung, die ein anderes Gesetz erfüllt, das die flip const Implementierung auch erfüllen würde.

Intuitiv scheint, angesichts des Ziels der Listenmonade ("nichtdeterministische Berechnungen"), die alternative Definition von >> genauso gut zu sein, wenn nicht sogar besser, da durch Beschneiden von Zweigen, die garantiert gleich sind, nur einer übrig bleibt. Oder anders ausgedrückt: Wenn wir mit Mengen anstelle von Listen arbeiten würden, wären die beiden Kandidaten-Definitionen äquivalent. Aber übersehe ich hier etwas, was die flip const-Definition falsch für Listen macht?

BEARBEITEN: Die Antwort von ehird behebt einen sehr offensichtlichen Fehler oben, nämlich dass sie das falsche beabsichtigte Ergebnis für [] >> k erhält, das [] sein sollte, nicht k. Dennoch denke ich, dass die Frage auf diese Definition abgeändert werden kann:

[] >> k = []
_ >> k = k

14voto

ehird Punkte 40404

a >> b muss immer gleichbedeutend sein mit a >>= const b; es ist nur in der Monad-Klasse vorhanden, damit Sie eine effizientere (aber semantisch äquivalente) Version definieren können. Deshalb gehört es nicht zu den Monadengesetzen: Es ist nicht wirklich Teil der Definition eines Monaden, sondern nur des Typklass (wie fail).

Leider konnte ich nirgendwo in der Dokumentation des base-Pakets finden, wo dies explizit angegeben ist, aber ich glaube, dass ältere Versionen möglicherweise (>>) außerhalb der Monad-Typklasse definiert haben.

Zu Ihrer Information, Ihre Definition von (>>) bricht die Verwendung der Listenmonade für nichtdeterministische Berechnungen. Da [] für Misserfolg steht, muss [] >> m immer [] sein; Sie können nicht fortfahren, nachdem Sie alle möglichen Zweige erschöpft haben! Das würde auch bedeuten, dass sich diese beiden Programme unterscheiden könnten:

do { m; ... }
do { _ <- m; ... }

da das erstere mit (>>) und das letztere mit (>>=) desugart. (Siehe den Haskell 2010 Report.)

4voto

ben w Punkte 2452

Weil ma >> mb nur eine Abkürzung für ma >>= \_ -> mb ist. Wenn >> als flip const nur im Falle von Listen definiert wäre, dann würde ma >> mb die Berechnung in ma überhaupt nicht ausführen, wenn ma eine Liste ist, was sehr verwirrend wäre.

Warum es nicht allgemein als flip const definiert ist, nun ja, die gegenwärtige Semantik von >> ermöglicht es, Effekte zu sequenzieren, wenn man sich nicht um ihre Ergebnisse kümmert, was oft nützlich ist.

2voto

pat Punkte 12485

Ihre Definition von >> verletzt das Assoziativitätsgesetz für Monad:

newtype B a = B { unB :: [a] }

instance Monad B where
  m >>= f = B . concatMap (unB.f) $ unB m
  (>>) = flip const
  return a = B [a]

case1 = B [1,2,3] >>= (\_ -> B [4,5,6] >> return 1)
case2 = (B [1,2,3] >>= \_ -> B [4,5,6]) >> return 1

main = do
  print $ unB case1
  print $ unB case2

Die beiden obigen Fälle unterscheiden sich in ihrer Assoziativität, führen aber zu unterschiedlichen Ergebnissen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X