softshipper
softshipper

Reputation: 34099

Why it has to be a monad?

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?

Upvotes: 2

Views: 151

Answers (3)

Redu
Redu

Reputation: 26191

fmap ((:) 3) []

Would actually apply the (:) 3 operator to the "contents" of your list functor. As you have no contents you normally get an empty list in return. If in case you had it like;

fmap ((:) 3) [[],[],[]]

then you would get [[3],[3],[3]] as the return value.

Now if you chose to feed fmap with a list value. You may feed it with a list value "wrapped" into List value constructor like;

*Main> fmap ((:) 3) $ return []
[3]

Upvotes: 1

Lee
Lee

Reputation: 144206

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.

Upvotes: 2

Mark Seemann
Mark Seemann

Reputation: 233347

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]

Upvotes: 8

Related Questions