本文介绍了GHC自动专业化的传递性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 29岁程序员,3月因学历无情被辞! 通过文档对于GHC 7.6: 和 AFAIK,答案是否,主要是,但有其他方式,并且不会。 代码内联和类型应用程序专门化是速度(执行时间)和代码大小之间的折中。默认级别可以获得一些加速而不会膨胀代码。通过 SPECIALIZE 编译指示选择更详尽的级别由程序员决定。 说明: 假设 f 是一个函数,其类型包含一个类型变量 a 被类型类 C a 约束。 GHC在默认情况下专门针对类型应用程序 f (用 a 代替 t f ,或者(b)如果 f 标记为 INLINABLE ,那么任何其他导入 f 来自 B 。因此,自动专门化不是传递的,它只触及 A的源代码中导入和调用的 INLINABLE 。 在你的例子中,如果你重写 Num 的实例如下: instance(Num r,Unbox r)=> Num(Qux r)其中(+)= quxAdd quxAdd(Qux x)(Qux y)= Qux $ U.zipWith(+)xy quxAdd 没有被主要。 Main 导入 Num(Qux Int)的实例字典,该字典包含 quxAdd 在(+)的记录中。但是,尽管字典已导入,但字典中使用的内容却不是。 plus 不会调用 quxAdd ,它使用存储的函数(+)记录在 Num t 的实例字典中。该字典在编译器的调用站点( Main )中设置。 From the docs for GHC 7.6:andSo GHC should automatically specialize some/most/all(?) functions marked INLINABLE without a pragma, and if I use an explicit pragma, the specialization is transitive. My question is:is the auto-specialization transitive?Specifically, here's a small example:Main.hs:import Data.Vector.Unboxed as Uimport Foomain = let y = Bar $ Qux $ U.replicate 11221184 0 :: Foo (Qux Int) (Bar (Qux ans)) = iterate (plus y) y !! 100 in putStr $ show $ foldl1' (*) ansFoo.hs:module Foo (Qux(..), Foo(..), plus) whereimport Data.Vector.Unboxed as Unewtype Qux r = Qux (Vector r)-- GHC inlines `plus` if I remove the bangs or the Baz constructordata Foo t = Bar !t | Baz !tinstance (Num r, Unbox r) => Num (Qux r) where {-# INLINABLE (+) #-} (Qux x) + (Qux y) = Qux $ U.zipWith (+) x y{-# INLINABLE plus #-}plus :: (Num t) => (Foo t) -> (Foo t) -> (Foo t)plus (Bar v1) (Bar v2) = Bar $ v1 + v2GHC specializes the call to plus, but does not specialize (+) in the Qux Num instance which kills performance.However, an explicit pragma {-# SPECIALIZE plus :: Foo (Qux Int) -> Foo (Qux Int) -> Foo (Qux Int) #-}results in transitive specialization as the docs indicate, so (+) is specialized and the code is 30x faster (both compiled with -O2). Is this expected behavior? Should I only expect (+) to be specialized transitively with an explicit pragma?UPDATEThe docs for 7.8.2 haven't changed, and the behavior is the same, so this question is still relevant. 解决方案 Short answers:The question's key points, as I understand them, are the following: AFAIK, the answers are No, mostly yes but there are other means, and No.Code inlining and type application specialization is a trade-off between speed (execution time) and code size. The default level gets some speedup without bloating the code. Choosing a more exhaustive level is left to the programmer's discretion via SPECIALISE pragma.Explanation:Suppose f is a function whose type includes a type variable a constrained by a type class C a. GHC by default specializes f with respect to a type application (substituting a for t) if f is called with that type application in the source code of (a) any function in the same module, or (b) if f is marked INLINABLE, then any other module that imports f from B. Thus, auto-specialization is not transitive, it only touches INLINABLE functions imported and called for in the source code of A.In your example, if you rewrite the instance of Num as follows: instance (Num r, Unbox r) => Num (Qux r) where (+) = quxAddquxAdd (Qux x) (Qux y) = Qux $ U.zipWith (+) x yquxAdd is not specifically imported by Main. Main imports the instance dictionary of Num (Qux Int), and this dictionary contains quxAdd in the record for (+). However, although the dictionary is imported, the contents used in the dictionary are not.plus does not call quxAdd, it uses the function stored for the (+) record in the instance dictionary of Num t. This dictionary is set at the call site (in Main) by the compiler. 这篇关于GHC自动专业化的传递性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
08-11 01:20