当newtype是Functor时,是否会删除对fmap的调用



如果我创建一个新类型:

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不见了,它只是对11求和。

如果您使用-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函数的名称篡改版本。

最新更新