Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why it has to be a monad?

Tags:

haskell

I've tried following code snippet on prelude:

*ExerciseMonad Control.Monad> :t fmap ((:) 3) []

and got as result an empty [].

Then I convert an empty list to monad structure:

*ExerciseMonad Control.Monad> x = return []
*ExerciseMonad Control.Monad> :t x
x :: Monad m => m [t]

the returned value is wrapped in Monad structure.

It seems like a magic, that I do not get an empty list:

*ExerciseMonad Control.Monad> fmap ((:) 3) x
[3]

Why did not I get an empty list?

like image 901
softshipper Avatar asked Jan 19 '26 18:01

softshipper


2 Answers

fmap works on any Functor, including []. Note how GHCi infers the type of your first expression:

Prelude> :t fmap ((:) 3) []
fmap ((:) 3) [] :: Num a => [[a]]

The return type is a nested list, because otherwise the cons operator (:) doesn't make sense. When you fmap over an empty list ([]), however, there's nothing to do, so the result is also the empty list.

On the other hand, the type of your second expression is different:

Prelude> x = return []
Prelude> :t x
x :: Monad m => m [t]
Prelude> :t fmap ((:) 3) x
fmap ((:) 3) x :: (Num a, Monad f) => f [a]

You'll notice that the return value is no longer a nested list, but a Monad over [a]. Monad, however, includes Applicative, which again includes Functor, so in this second expression, fmap is no longer the for the [] instance, but for f. As Lee points out, in GHCi, the default Monad is IO, so the fmap in fmap ((:) 3) x maps IO, not [].

This means that x actually becomes IO [] in GHCi, and fmap in the IO monad applies the mapping function to the data contained inside of the monad ([]). This means that you get ((:) 3) [], which is [3]:

Prelude> ((:) 3) []
[3]
like image 76
Mark Seemann Avatar answered Jan 23 '26 09:01

Mark Seemann


In your first example fmap ((:) 3) [] has type Num a => [[a]]. fmap f [] == [].

In contrast the type of fmap ((:) 3) x is (Monad m, Num a) => m [a].GHCi deafults m to IO so at the prompt it has type Num a => IO [a]. The corresponding IO action is evaluated and the result is printed if it is an instance of Show. a defaults to Integer and [Integer] has a Show instance so it is displayed.

like image 28
Lee Avatar answered Jan 23 '26 07:01

Lee



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!