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

如果我创建一个新类型:

newtype Bloo a = Bloo a 

并使其成为函子

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函数的名称错误版本。


以上是当newtype是Functor时,会删除对fmap的调用吗?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>