Haskell function which acts differently depending on the monad type

137 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
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
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.