I can define a natural transformation in Haskell as:
h :: [a] -> Maybe a
h [] = Nothing
h (x:_) = Just x
and with a function k:
k :: Char -> Int
k = ord
the naturality condition is met due to the fact that:
h . fmap k == fmap k . h
Can the naturality condition of the List monad's join function be demonstrated in a similar way? I'm having some trouble understanding how join, say concat in particular, is a natural transformation.
Okay, let's look at concat.
First, here's the implementation:
concat :: [[a]] -> [a]
concat = foldr (++) []
This parallels the structure of your h where Maybe is replaced by [] and, more significantly, [] is replaced by--to abuse syntax for a moment--[[]].
[[]] is a functor as well, of course, but it's not a Functor instance in the way that the naturality condition uses it. Translating your example directly won't work:
concat . fmap k =/= fmap k . concat
...because both fmaps are working on only the outermost [].
And although [[]] is hypothetically a valid instance of Functor you can't make it one directly, for practical reasons that are probably obvious.
However, you can reconstruct the correct lifting as so:
concat . (fmap . fmap) k == fmap k . concat
...where fmap . fmap is equivalent to the implementation of fmap for a hypothetical Functor instance for [[]].
As a related addendum, return is awkward for the opposite reason: a -> f a is a natural transformation from an elided identity functor. Using : [] the identity would be written as so:
(:[]) . ($) k == fmap k . (:[])
...where the completely superfluous ($) is standing in for what would be fmap over the elided identity functor.
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