I know that the dot (.) operator takes two functions which both take an argument respectively, and the third argument for the second argument.
Its type is (.) :: (b -> c) -> (a -> b) -> a -> c.
For example, take 1 . drop 2 $ [1,2,3,4,5].
But how can (fmap . const) work?
The fmap function needs two arguments, and the const function takes two arguments and then return the first argument.
So logically, the fmap should take the output which is the first argument taken by the const function.
The types of two functions:
fmap :: Functor f => (a -> b) -> f a -> f b
const :: a -> b -> a
The fmap in (fmap . const) 2 (Just 4) should get the output 2 returned by the const function, so it'd not work, but actually it does work.
What happened?
The
fmapfunction needs two arguments, and theconstfunction takes two arguments and then return the first argument.
No, every function takes one parameter, and sometimes produces a function as result. fmap :: Functor f => (a -> b) -> (f a -> f b), takes one function, of type a -> b, and then produces a function that maps an f a to an f b.
Now, the same trick is necessary when we work with const :: c -> d -> c, this is short for const :: c -> (d -> c), so again, a function that takes a value, and then produces a function that will map any value to the given value.
So then what is fmap . const? It is short for \x -> fmap (const x). It thus asks for a value x, and then produces an fmap (const x), this thus means that fmap will map any value to x. This thus means that if we work for example with x = 42, and a list [1,4,2,5], we get fmap (const 42) [1,4,2,5], and this thus means that we map any item of the list to 42, so [42, 42, 42, 42].
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