如果我创建一个新类型:
newtype Bloo a = Bloo a
并使其成为Functor
instance Functor Bloo where
fmap f (Bloo a) = Bloo $ f a
fmap f (Bloo a)
转换为
f a
在编译的程序中?
几乎可以肯定,是的,但它确实需要内联fmap
,这在某些情况下可能不会发生。例如,如果它被认为很大(在这种情况下并不真正相关(,或者如果您使用{-# NOINLINE fmap #-}
注释对其进行注释。在这些情况下,它只是一个将f
应用于其参数的函数,如:fmap f x = f x
。
你可以自己试试。以这个代码为例:
-- 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)
并用ghc Test.hs -ddump-simpl -dsuppress-all -fforce-recomp
进行编译。这将输出一堆东西,但在某个地方你会发现main
函数:
-- RHS size: {terms: 8, types: 9, coercions: 3, joins: 0/0}
main
= $ (print ($fShowTest $fShowInteger))
((+ $fNumInteger 1 1) `cast` <Co:3>)
如果你斜视一点,你可能会看到fmap
不见了,它只是对1
和1
求和。
如果您使用-O1
启用优化,那么它甚至会在编译时评估1 + 1
:
-- 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
这个输出有点模糊,但我希望你能认出main3 = 2
,这是1 + 1
的结果。
如果您添加{-# NOINLINE fmap #-}
杂注(并再次禁用优化(,您将得到:
-- 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>))
这也很复杂,但您可能会认出$cfmap1_r1CZ
,它是fmap
函数的名称篡改版本。