2013-05-06 6 views
6

Est-il sensé de définir plusieurs méthodes flatMap (ou >>=/bind dans Haskell) dans une Monade? Les très rares monades que j'utilise réellement (projections Option, Try, Either) ne définissent qu'une seule méthode flatMap.Plusieurs méthodes flatMap pour une seule monade?

Par exemple, est-il possible de définir une méthode flatMap sur Option qui prendrait une fonction produisant un Try? Alors que Option[Try[User]] serait aplati comme Option[User] par exemple? (Considérant que la perte de l'exception n'est pas un problème ...)

Ou une monade doit simplement définir une méthode flatMap, en prenant une fonction qui produit le même type de monade? Je suppose que dans ce cas, les projections Either ne seraient pas des monades? Sont-ils?

+0

@ om-nom-nom et La liste est une Monade alors? Par ailleurs, je ne peux pas trouver comment cela fonctionne pour 'List [Option [_]]' depuis Option n'est pas un GenTraversableOnce –

+0

'Sither' est une monade sur ses deux variables de type. Est-ce ce que vous demandez? –

Répondre

5

J'ai déjà sérieusement pensé à cela. Comme il se trouve, une telle construction (en dehors de perdre toutes les capacités monades) n'est pas vraiment intéressant, car il suffit de fournir une conversion de l'intérieur vers le récipient extérieur:

joinWith :: (Functor m, Monad m) => (n a -> m a) -> m (n a) -> m a 
joinWith i = join . (fmap i) 

bindWith :: (Functor m, Monad m) => (n a -> m a) -> m a -> (a -> n a) -> m a 
bindWith i x f = joinWith i $ fmap f x 

*Main> let maybeToList = (\x -> case x of Nothing -> []; (Just y) -> [y]) 
*Main> bindWith maybeToList [1..9] (\x -> if even x then Just x else Nothing) 
[2,4,6,8] 
+2

Ceci est une bonne réponse. Je crois comprendre que cela correspond bien à la théorie: la fonction 'n a -> m a' représente une transformation naturelle entre les foncteurs' n' et 'm'. En supposant qu'il respecte les opérations de la monade, il représente aussi un homomorphisme de monade entre 'n' et' m'. –

+0

Désolé votre réponse est astucieuse, cela ne répond pas à la question "Méthodes FlatMap multiples pour une seule monade?". Bien sûr, nous pouvons trouver un moyen de fusionner deux monades différentes en une seule, mais faire ce genre de transformation conduit-elle aussi à une monade? Et je ne vois pas comment votre réponse peut l'aider à comprendre pourquoi ce n'est pas une monade. – zurgl

+0

cette réponse est presque parfaite, imo. L'autre chose que je voudrais souligner est que si vous aviez une fonction 'ma -> (a -> nb) -> nb' qui obéissait aux lois monadiques, vous pourriez construire un morphisme de monade' ma -> nb' en lui passant '' return' comme deuxième argument. Simultanément, une fonction comme 'm a -> (a -> n b) -> m b' peut être transformée en un morphisme monade' n a -> m b' avec un peu plus de travail. –

1

Cela dépend de ce que signifie "faire sens". Si vous voulez dire est-ce compatible avec les lois de la monade, alors il n'est pas tout à fait clair pour moi que la question est tout à fait logique. Je devrais voir une proposition concrète à dire. Si vous le faites comme je le suggère, vous finirez probablement par violer la composition au moins dans certains cas.

Si vous voulez dire est-ce utile, bien sûr, vous pouvez toujours trouver des cas où de telles choses sont utiles. Le problème est que si vous commencez à violer les lois de la monade, vous avez laissé des pièges dans votre code pour le raisonnement fonctionnel imprudent (théorie de la catégorie). Mieux vaut faire en sorte que les choses qui ressemblent un peu à des monades soient des monades (et juste une à la fois, bien que vous puissiez fournir une manière explicite de changer la Either - mais vous avez raison que les écritures LeftProjection et RightProjection ne le sont pas, strictement parlant, monades). Ou écrire des documents vraiment clairs expliquant que ce n'est pas ce à quoi ça ressemble. Sinon, quelqu'un va gaiement aller de l'avant en supposant que les lois tiennent, et * splat *.

1

Cela n'a pas de sens, pour un type de données spécifique, autant que je sache, vous ne pouvez avoir qu'une définition pour bind.

En haskell une monade est la classe de type suivant,

instance Monad m where 
    return :: a -> m a 
    bind :: m a -> (a -> m b) -> m b 

Pour la liste Monad Concrètement, nous avons,

instance Monad [] where 
    return :: a -> [] a 
    (>>=) :: [] a -> (a -> [] b) -> [] b 

Considérons maintenant une fonction monadique comme.

actOnList :: a -> [] b 
.... 

un cas d'utilisation pour illustrer,

$ [1,2,3] >>= actOnList 

Sur la fonction actOnList on voit qu'une liste est une contrainte de type polymorphes par un autre type (ici []). Ensuite, quand nous parlons de l'opérateur bind pour la liste monad nous parlons de l'opérateur bind défini par [] a -> (a -> [] b) -> [] b.

Qu'est-ce que vous voulez atteindre est un opérateur bind défini comme [] Maybe a -> (a -> [] b) -> [] b, ce pas une version specialize de la première, mais une autre fonction et à son sujet signature de type je doute vraiment qu'il peut être l'opérateur bind de toute sorte de monade comme vous ne retournez pas ce que vous avez consommé.Vous allez sûrement d'une monade à l'autre en utilisant une fonction mais cette fonction n'est certainement pas une autre version de l'opérateur bind de la liste.

C'est pourquoi je l'ai dit, Cela n'a pas de sens, pour un type de données spécifique, autant que je sache, vous ne pouvez avoir qu'une définition pour bind.

1

flatMap ou (>>=) ne correspond pas à votre exemple Option[Try[ ]]. Dans la notation pseudo-Haskell

type OptionTry x = Option (Try x) 

instance Monad OptionTry where 
    (>>=) :: OptionTry a -> (a -> OptionTry b) -> OptionTry b 
    ... 

Nous avons besoin bind/flatMap pour retourner une valeur enveloppée dans le même contexte que la valeur d'entrée.

Nous pouvons également voir cela en regardant l'équivalent return/join la mise en œuvre d'une Monade. Pour OptionTry, join a le type spécialisé

instance Monad OptionTry where 
    join :: OptionTry (OptionTry a) -> OptionTry a 
    ... 

Il doit être clair avec un peu de plisser les yeux que la partie « plate » de flatMap est join (ou concat pour les listes où le nom dérive de).

Maintenant, il est possible qu'un seul type de données ait plusieurs bind s différents. Mathématiquement, une Monad est en fait le type de données (ou, en réalité, l'ensemble des valeurs que la monade se compose) avec les opérations bind et return. Différentes opérations conduisent à différentes monades (mathématiques).