融合技术能否穿透新类型包装器?

20

给定:

newtype MyVec = MyVec { unVec :: Data.Vector } 
  deriving (Functor, etc)

这将创建(类似于)这个:

instance Functor MyVec where
  fmap f = MyVec . Data.Vector.fmap f . unVec

向量的融合规则会触发并将fmap f . fmap g $ myVec重写为fmap (f . g) myVec吗?

我需要注意哪些陷阱?据我所知,在GHC 7.8中解决了在容器中使用新类型的问题,是这样吗?

1个回答

17

融合规则是在函数上操作的,而不是在类型上操作的。除非你编写了重用基础规则的函数,否则你在MyVec上的函数将没有融合规则。

例如:

map :: (a -> b) -> MyVec a -> MyVec b
map f = MyVec . Vector.map f . unVec
{-# INLINE map #-}

那么我们将有以下用途:

map f . map g

这将会内联到:

MyVec . Vector.map f . unVec . MyVec . Vector.map g . unVec

GHC应当在擦除newtype构造器后,得到一个普通的流,适用于融合:

MyVec . Vector.map f . Vector.map g . unVec

你可以通过运行GHC并查看重写规则的启动来确认这一点。或者,你可以添加自己的 "MyVec. unVec" 重写规则,但是GHC应该已经涵盖了这一点。

1
Haskell维基百科指出:“newtype不会产生任何开销”。如果它确实阻止了某些优化,那么它不应该被重新表述吗? - gallais
map 的定义中不应该调用 MyVec 吗?例如: map f x = MyVec $ Vector.map f (unVec x) - ErikR
1
第一个问题:我如何了解相关的重写规则。当我使用“-ddump-rule-firings”时,我看到了成千上万次的触发...其中哪些是相关的? - fho
2
第二个问题:通用的新类型派生代码会自动内联吗?否则,我该如何将 INLINE(或更好的 INLINABLE?)指示符附加到派生类型类? - fho

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接