ghci> :t pure []
pure [] :: Applicative f => f [a]
ghci> pure []
[]
ghci> :t []
[] :: [a]
ghci> fmap ((:) 2) (pure [])
[2]
ghci> fmap ((:) 2) ([])
[]
I would have thought replacing pure[]
with []
in fmap ((:) 2) (pure [])
would result in the same outcome.. who can explain the difference to me?
pure encapsulates a value into an arbitrary Applicative functor. Hence, pure 0 can mean any of: Just 0 , [0] , \_ -> 0 , (mempty, 0) , etc. Also note that return = pure .
Definition. In Haskell, an applicative is a parametrized type that we think of as being a container for data of that type plus two methods pure and <*> . Consider a parametrized type f a . The pure method for an applicative of type f has type. pure :: a -> f a.
From HaskellWiki. A function is called pure if it corresponds to a function in the mathematical sense: it associates each possible input value with an output value, and does nothing else.
The type of pure
is Applicative f => a -> f a
so pure []
has type Applicative f => f [a]
. You can specify f
explicitly for different applicative types e.g.
pure [] :: Maybe [String] //Just []
pure [] :: IO [String] //displays '[]' in ghci
pure [] :: [[String]] //[[]]
The type of fmap ((:) 2) (pure [])
is (Applicative f, Num a) => f [a]
. Since Ghci runs in the IO monad, which is an Applicative
, it chooses f
to be IO
, and displays the resulting list [2]
which is what you see.
You can specify the applicative type directly to see a different result e.g.
fmap ((:) 2) (pure []) :: (Maybe [Int])
which is Just [2]
In fmap ((:) 2) ([])
, there are no elements in the input list so you get an empty list.
Why would it be the same? They're different expressions.
Perhaps it simplifies things if we just look at lists. So, there's the empty list []
. Its type can be anything with brackets around it, in particular also a nested list:
Prelude> [] :: [[Int]]
[]
But there's also another "empty nested list":
Prelude> [[]] :: [[Int]]
[[]]
This one isn't really empty though, it merely contains only the empty list. ([[],[],[],...]
would also be possible). In fact, that would be the result of what you've tried, if done in the list applicative:
Prelude Control.Applicative> pure [] :: [[Int]]
[[]]
It is certainly not the same as the empty list,
Prelude> [[]] == []
False
In particular,
Prelude> (length [], length [[]])
(0,1)
And fmap
pming over an empty list never does anything, while fmap
ping over an empty-containing list will call the function with []
: an easy way to see this is
Prelude Control.Applicative> fmap undefined []
[]
Prelude Control.Applicative> fmap undefined [[]]
[* Exception: Prelude.undefined
The real confusing thing about your trials is that ghci silently uses the IO
monad.
There's also a subclass of Applicative
for actual emptiness:
Prelude Control.Applicative> :i Alternative
class Applicative f => Alternative f where
empty :: f a
(<|>) :: f a -> f a -> f a
some :: f a -> f [a]
many :: f a -> f [a]
-- Defined in `Control.Applicative'
instance Alternative [] -- Defined in `Control.Applicative'
instance Alternative Maybe -- Defined in `Control.Applicative'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With