91 votes

Distinction entre les classes de type MonadPlus, Alternative, et Monoid ?

Les classes de type Haskell de la bibliothèque standard MonadPlus , Alternative y Monoid fournissent chacune deux méthodes ayant essentiellement la même sémantique :

  • Une valeur vide : mzero , empty ou mempty .
  • Un opérateur a -> a -> a qui joint les valeurs de la classe de type ensemble : mplus , <|> ou mappend .

Tous trois précisent ces lois auxquelles les instances doivent se conformer :

mempty `mappend` x = x
x `mappend` mempty = x

Ainsi, il semble que les trois classes de type fournissent toutes les informations suivantes même métodos.

( Alternative fournit également some y many mais leurs définitions par défaut sont généralement suffisantes, et elles ne sont donc pas trop importantes pour cette question).

Ma question est donc la suivante : pourquoi ces trois classes sont-elles extrêmement similaires ? Y a-t-il une réelle différence entre elles, en dehors de leurs contraintes de superclasse différentes ?

0 votes

C'est une bonne question. En particulier, Applicative y MonadPlus semblent être exactement les mêmes (modulo les contraintes de superclasse).

1 votes

Il y a aussi ArrowZero y ArrowPlus pour les flèches. Mon pari : rendre les signatures de type plus propres (ce qui rend les contraintes de superclasse différentes le site réelle différence).

4 votes

@CatPlusPlus : bien, ArrowZero y ArrowPlus avoir une sorte * -> * -> * ce qui signifie que vous pouvez les passer pour le type de flèche une seule fois pour une fonction qui doit les utiliser pour une multitude de types, pour utiliser une Monoid vous devez exiger une instance de Monoid pour chaque instanciation particulière, et vous n'auriez aucune garantie qu'elles soient traitées de la même manière, les instances pourraient ne pas être liées !

125voto

Edward Kmett Points 18369

MonadPlus y Monoid servent des objectifs différents.

A Monoid est paramétrée sur un type de type * .

class Monoid m where
    mempty :: m
    mappend :: m -> m -> m

et il peut donc être instancié pour presque tous les types pour lesquels il existe un opérateur évident qui est associatif et qui a une unité.

Cependant, MonadPlus ne spécifie pas seulement que vous avez une structure monoïdale, mais aussi que cette structure est liée à la façon dont les Monad travaux, y que cette structure ne se soucie pas de la valeur contenue dans la monade, ceci est (en partie) indiqué par le fait que MonadPlus prend un argument de type * -> * .

class Monad m => MonadPlus m where
    mzero :: m a
    mplus :: m a -> m a -> m a

En plus des lois du monoïde, nous avons deux ensembles potentiels de lois que nous pouvons appliquer à MonadPlus . Malheureusement, la communauté n'est pas d'accord sur ce qu'ils devraient être.

Au moins, nous savons

mzero >>= k = mzero

mais il y a deux autres extensions concurrentes, la loi de distribution de gauche (sic)

mplus a b >>= k = mplus (a >>= k) (b >>= k)

et la loi de la prise à gauche

mplus (return a) b = return a

Ainsi, toute instance de MonadPlus doit satisfaire à l'une ou aux deux lois supplémentaires.

Alors qu'en est-il Alternative ?

Applicative a été défini après Monad et appartient logiquement à une superclasse de Monad mais en grande partie à cause des pressions différentes exercées sur les concepteurs à l'époque de Haskell 98, même Functor n'était pas une superclasse de Monad jusqu'en 2015. Maintenant, nous avons enfin Applicative comme une superclasse de Monad dans GHC (si ce n'est pas encore dans un standard de langage).

Efficacement, Alternative est de Applicative ce que MonadPlus est de Monad .

Pour ceux-ci, nous aurions

empty <*> m = empty

de manière analogue à ce que nous avons avec MonadPlus et il existe des propriétés distributives et d'accrochage similaires, dont au moins une que vous devez satisfaire.

Malheureusement, même empty <*> m = empty La loi est une affirmation trop forte. Elle ne tient pas pour À l'envers par exemple !

Lorsque nous regardons MonadPlus, la loi vide >>= f = vide nous est presque imposée. La construction vide ne peut pas contenir de 'a' pour appeler la fonction f avec de toute façon.

Toutefois, étant donné que Applicative es no une superclasse de Monad y Alternative es no une superclasse de MonadPlus nous finissons par définir les deux instances séparément.

En outre, même si Applicative était une superclasse de Monad vous auriez besoin de la MonadPlus de toute façon, parce que même si nous obéissions

empty <*> m = empty

ce n'est pas strictement suffisant pour prouver que

empty >>= f = empty

Donc, prétendre que quelque chose est MonadPlus est plus fort que de prétendre que c'est Alternative .

Maintenant, par convention, le MonadPlus y Alternative pour un type donné devraient concorder, mais les Monoid peut être complètement différent.

Par exemple, le MonadPlus y Alternative para Maybe faire la chose la plus évidente :

instance MonadPlus Maybe where
    mzero = Nothing
    mplus (Just a) _  = Just a
    mplus _        mb = mb

mais le Monoid L'instance transforme un semigroupe en un Monoid . Malheureusement, parce qu'il n'existait pas de Semigroup à l'époque en Haskell 98, elle le fait en exigeant une classe Monoid mais sans utiliser son unité. _

instance Monoid a => Monoid (Maybe a) where
    mempty = Nothing
    mappend (Just a) (Just b) = Just (mappend a b)
    mappend Nothing x = x
    mappend x Nothing = x
    mappend Nothing Nothing = Nothing

TL;DR MonadPlus est une affirmation plus forte que Alternative qui, à son tour, est une affirmation plus forte que Monoid et alors que le MonadPlus y Alternative les instances d'un type doivent être liées, la Monoid peut être (et est parfois) quelque chose de complètement différent.

1 votes

Une réponse très perspicace ! Je n'avais pas réalisé, en particulier, que empty <*> m = empty n'implique pas empty >>= f = empty .

2 votes

Excellente réponse, cependant la dernière définition semble être erronée, elle ne satisfait pas mempty `mappend` x x .

0 votes

@Vitus : Correct. La définition est Nothing `mappend` x = x et vice versa.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X