Haskell function which acts differently depending on the monad type

159 Views Asked by At

I'm trying to implement a function which usually puts the first element of a list in a monad, but if the monad is a list it returns the whole list:

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

Should return Just 1, and

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

should return [1,2,3].

Any ideas?

2

There are 2 best solutions below

1
marc On BEST ANSWER

In your particular use-case, you could take advantage of msum:

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

Then both examples will work:

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

Note however that Maybe is not exactly MonadPlus, since mplus there is not associative.

2
chepner On

In general, you can't do this, because the function cannot know which Foo instance will be used when the function is called, meaning it has no basis for deciding to return return s or return (s:sx).

In this particular case, there is a workaround (see @marc's answer) when Foo is MonadPlus.