使用GADT的性能影响

yat*_*975 9 performance haskell gadt

回答有关使用GADT的建议的问题时,评论中提出了一些与性能有关的问题.问题涉及类型类PlotValue:

class PlotValue a where
    value :: a -> Double
Run Code Online (Sandbox Code Playgroud)

我的回答建议使用GADT Input:

data Input where
    Input :: (PlotValue a, PlotValue b) => Maybe a -> Maybe b -> Input
Run Code Online (Sandbox Code Playgroud)

但我认为细节并不重要.

我想知道性能的两个方面:

时间:模式匹配是否会产生任何运行时成本

case x of
    Input (Just a) (Just b) -> value a * value b
    _ -> 0.0
Run Code Online (Sandbox Code Playgroud)

超过正常成本匹配两个Maybe值?

空间:类型值Input携带多少存储开销?我的猜测是它PlotValue为每个类型的值Input(每个都有一个'指针')带有两个字典,这意味着[Input]在内存使用方面,a比使用更低效,(Just Double, Just Double)或者更好的是,(# #Double, #Double #)- 如果你存储结果value在正常或解压后的元组.

所以,虽然我喜欢GADT给我的表现力,但我从未想过表现方面.任何人都可以告诉我更多关于这个(以及我可能不知道的任何其他隐藏成本)?

aug*_*tss 13

我认为你已经确定了开销.对于每个存在限定变量,您需要相应的(指向)字典.这需要空间,更糟糕的是,方法调用将变得缓慢.你的例子中的(*)将是一个间接函数调用,而对于Double,它将是一个原始的op.

  • 但是,关于OOP和非final类的对象(传递给方法的每个这样的对象都需要指向虚方法表或等价的指针)的类似声明都是正确的,并且C++或Java对于大量应用程序来说足够高性能.当然,在这两种语言中,您都会使用非OO之类的东西,例如数组来表示性能.明显的评论,但我想把它放在透视中. (2认同)
  • 谢谢你的回答,证实了我的怀疑!在case表达式中的`(*)`在我看来它总是在类型`Double - > Double - > Double`中使用,因为`value`的结果是`Double`,但是`value`将一直在评估并且可能很昂贵(比如解析一个`String`)所以这里简单的`Double`s会做得更好. (2认同)