Reputation: 5459
If I create a newtype:
newtype Bloo a = Bloo a
And make it a Functor
instance Functor Bloo where
fmap f (Bloo a) = Bloo $ f a
Will
fmap f (Bloo a)
be converted to
f a
in the compiled program?
Upvotes: 6
Views: 106
Reputation: 10645
Almost certainly, yes, but it does require fmap
to be inlined, which may not happen under certain circumstances. For example if it is deemed to large (not really relevant in this case) or if you annotate it with a {-# NOINLINE fmap #-}
annotation. In those cases it will just be a function that applies f
to its argument, like: fmap f x = f x
.
You can try it out for yourself. Take this code for example:
-- Test.hs
newtype Test a = Test a
deriving Show
instance Functor Test where
fmap f (Test x) = Test (f x)
main = print $ fmap (+ 1) (Test 1)
And compile it with ghc Test.hs -ddump-simpl -dsuppress-all -fforce-recomp
. That will output a bunch of stuff, but somewhere you will find the main
function:
-- RHS size: {terms: 8, types: 9, coercions: 3, joins: 0/0}
main
= $ (print ($fShowTest $fShowInteger))
((+ $fNumInteger 1 1) `cast` <Co:3>)
If you squint a bit, you might see that the fmap
is gone and it is simply summing 1
and 1
.
If you enable optimizations with -O1
then it will even evaluate that 1 + 1
at compile time:
-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
main3 = 2
-- RHS size: {terms: 9, types: 11, coercions: 0, joins: 0/0}
main2
= case $w$cshowsPrec4 11# main3 [] of { (# ww3_a2vc, ww4_a2vd #) ->
: ww3_a2vc ww4_a2vd
}
-- RHS size: {terms: 3, types: 1, coercions: 0, joins: 0/0}
main1 = ++ $fShowTest2 main2
-- RHS size: {terms: 4, types: 0, coercions: 0, joins: 0/0}
main = hPutStr' stdout main1 True
This output is a bit more obscure, but I hope you can recognize main3 = 2
which is the result of 1 + 1
.
If you add a {-# NOINLINE fmap #-}
pragma (and disable optimizations again) you will get:
-- RHS size: {terms: 13, types: 13, coercions: 3, joins: 0/1}
main
= $ (print ($fShowTest $fShowInteger))
($cfmap1_r1CZ
(let { ds_d1Cs = 1 } in
\ ds1_d1Cr -> + $fNumInteger ds1_d1Cr ds_d1Cs)
(1 `cast` <Co:3>))
Which is also complicated, but you might recognize $cfmap1_r1CZ
which is a name-mangled version of the fmap
function.
Upvotes: 11