I was playing around with functors, and I noticed something interesting:
Trivially, id
can be instantiated at the type (a -> b) -> a -> b
.
With the list functor we have fmap :: (a -> b) -> [a] -> [b]
, which is the same as map
.
In the case of the ((->) r)
functor (from Control.Monad.Instances
), fmap
is function composition, so we can instantiate fmap fmap fmap :: (a -> b) -> [[a]] -> [[b]]
, which is equivalent to (map . map)
.
Interestingly, fmap
eight times gives us (map . map . map)
!
So we have
0: id = id
1: fmap = map
3: fmap fmap fmap = (map . map)
8: fmap fmap fmap fmap fmap fmap fmap fmap = (map . map . map)
Does this pattern continue? Why/why not? Is there a formula for how many fmap
s I need to map a function over an n-times nested list?
I tried writing a test script to search for a solution to the n = 4 case, but GHC starts eating too much memory at around 40 fmap
s.
(.)
asfmap
.) – ehirdfmap
n = 4k times (for n at least 8) gives(map . map . map)
. I'm still curious about why this happens, though. Especially because the instances change. At n = 8 it's(.) (.) (.) (.) (.) map map map
, while for n = 12 it's(.) (.) (.) (.) (.) (.) (.) (.) map (.) map map
. – hammar