2014-04-11 10 views
33

Ich versuche die Motivation hinter dem MonadPlus zu verstehen. Warum ist es notwendig, wenn bereits die Typklassen Monad und Monoid vorhanden sind?Warum MonadPlus und nicht Monad + Monoid?

Zugegeben, Instanzen von Monoid sind konkrete Typen, während Instanzen von Monad einen einzelnen Typparameter erfordern. (Siehe Monoid vs MonadPlus für eine hilfreiche Erklärung.) Aber könnte man umschreiben keinerlei Einschränkung von

(MonadPlus m) => ... 

als eine Kombination von Monad und Monoid?

(Monad m, Monoid (m a)) => ... 

Nehmen Sie die guard Funktion von Control.Monad, zum Beispiel. Seine Umsetzung ist:

guard :: (MonadPlus m) => Bool -> m() 
guard True = return() 
guard False = mzero 

ich es umsetzen konnte nur mit Monad und Monoid:

guard' :: (Monad m, Monoid (m())) => Bool -> m() 
guard' True = return() 
guard' False = mempty 

Könnte jemand bitte den wirklichen Unterschied zwischen MonadPlus und Monad + Monoid klären?

Antwort

32

Aber könnten Sie jede Art von Zwang

(MonadPlus m) => ... 

als eine Kombination von Monad und Monoid nicht neu schreiben?

Nein. In der oberen Antwort auf die Frage, die Sie verknüpfen, gibt es bereits eine gute Erklärung über die Gesetze von MonadPlus vs. Monoid. Aber selbst wenn wir die Klassengesetze ignorieren, gibt es Unterschiede.

Monoid (m a) => ... bedeutet, dass m a hat ein monoid für eine bestimmte a vom Anrufer gewählt sein, sondern bedeutet, dass MonadPlus mm a ein monoid für alle a sein muss. So MonadPlus a ist flexibler, und diese Flexibilität ist nützlich in vier Situationen:

  1. Wenn wir nicht wollen, um den Anrufer zu sagen, was a wir beabsichtigen, zu verwenden.
    MonadPlus m => ... statt Monoid (m SecretType) => ...

  2. Wenn wir mehrere verschiedene a verwenden möchten.
    MonadPlus m => ... statt (Monoid (m Type1), Monoid (m Type2), ...) => ...

  3. Wenn wir unendlich viele verschiedene a verwenden möchten.
    MonadPlus m => ... statt nicht möglich.

  4. Wenn wir nicht wissen, was a wir brauchen. MonadPlus m => ... statt nicht möglich.

+0

Wenn es Ihnen nichts ausmacht würde ich gerne ein konkretes Beispiel hier sehen. Können Sie einige Instanzen mit bestimmten Monaden bereitstellen, in denen MonadPlus nützlicher oder sauberer ist als Monoid? – Fresheyeball

+0

@Fresheyeball: Nein, ich kann "einige Instanzen mit bestimmten Monads" nicht anbieten, sorry. Wenn die Monade bekannt ist, besteht keine Notwendigkeit, über m zu abstrahieren, und es ist nicht notwendig, irgendwelche Typklassen zu verwenden, um die erwartete Schnittstelle von m zu spezifizieren, so dass der Unterschied zwischen MonadPlus und Monoid nicht wirklich von Bedeutung ist funktioniert nur mit einer bestimmten Monade. – Toxaris

+0

Ich verstehe das. Aber es ist schwierig, die Praxis zu verstehen, ohne zu sehen, wie bestimmte Monaden mit verallgemeinerten Codes arbeiten würden. – Fresheyeball

6

Ihr guard' stimmt nicht mit Ihrem Monoid m a Typ überein. Wenn Sie meinen, Monoid (m a), dann müssen Sie definieren, was mempty für m() ist. Sobald Sie das getan haben, haben Sie eine MonadPlus definiert.

In anderen Worten definiert MonadPlus zwei opeartions: mzero und mplus zwei Regeln erfüllen: mzero zu mplus bezüglich neutral ist, und mplus ist assoziativ. Dies erfüllt die Definition von Monoid, so dass mzeromempty und mplusmappend ist.

Der Unterschied besteht darin, dass MonadPlus m ist ein monoid m a für jede a, aber Monoid m definiert eine monoid nur für m. Ihr guard' funktioniert, weil Sie nur m zu einem Monoid nur für () benötigen. Aber MonadPlus ist stärker, es beansprucht m a, ein Monoid für irgendeinen a zu sein.

Verwandte Themen