2017-02-02 1 views
1

J'essaye d'implémenter une fonction qui place habituellement le premier élément d'une liste dans une monade, mais si la monade est une liste, elle renvoie la liste entière:Fonction Haskell qui agit différemment selon le type de monade

putInMonad :: MonadPlus m => [a] -> m a 
putInMonad (s:sx) = return s 
putInMonad _ = mzero 
putInMonad [1,2,3] :: Maybe Int 

devrait revenir Just 1 et

putInMonad [1,2,3] :: [] Int 

devrait revenir [1,2,3].

Des idées?

+0

Vous pouvez utiliser '[[]] Int' comme monade inférieure. –

+0

@WillemVanOnsem Non, car l'expression 'return s' ne contient aucune information sur' sx'; Le simple fait de fournir un type de retour concret n'aide pas. – chepner

+0

@chepner: ouais je sais qu'il ne se comportera pas différemment pour cette monade spécifique. J'ai seulement eu l'idée de résoudre le problème de l'autre côté: donnez-lui une liste de listes au lieu d'une liste d'éléments. –

Répondre

5

Dans votre cas d'utilisation particulier, vous pouvez profiter de msum:

putInMonad :: MonadPlus m => [a] -> m a 
putInMonad x = msum $ map return x 

Ensuite, les deux exemples fonctionneront:

% putInMonad [1,2,3,4] :: Maybe Int 
Just 1 
% putInMonad [1,2,3,4] :: [Int] 
[1,2,3,4] 

Notez cependant que Maybe est pas exactement MonadPlus, depuis mplus il n'est pas associatif.

+4

Tout malaise/controverse à propos de 'MonadPlus' pourrait être évité en passant à' Alternative' et 'asum', si la contrainte' MonadPlus' n'est pas une exigence stricte pour l'OP. – duplode

1

En général, vous ne pouvez pas faire cela, parce que la fonction ne peut pas savoir quelle Foo instance sera utilisé lorsque la fonction est appelée, ce qui signifie qu'il n'a pas de base pour décider de retourner return s ou return (s:sx). Dans ce cas particulier, il existe une solution de contournement (voir @marc's answer) lorsque Foo correspond à MonadPlus.

+0

En attente de votes pour me dire si je suis techniquement correct, ou tout simplement faux plat. – chepner

+0

Vous n'êtes pas techniquement correct, mais simplement parce que la classe en question est «MonadPlus», qui offre la solution de contournement indiquée dans la réponse de Marc. Que cela soit impossible dans le cas général est encore un point qui vaut la peine d'être fait. Je suggère d'éditer votre réponse pour clarifier cette subtilité et/ou pointer vers la réponse de Marc pour le contraste. – duplode