Haskell中高效的重载技术

6

我想知道以下两种策略对于重载函数(在我的例子中是teX函数)来说哪一种更加高效。

  1. Using data and pattern matching:

    data TeX
      = TeXt String
      | TeXmath String
      deriving (Show,Read,Eq)
    teX (TeXt t)    = t
    teX (TeXmath t) = "$$" ++ t ++ "$$"
    
  2. Or using a bit of abstraction:

    class TeX t where
      teX :: t -> String
    
    newtype TeXt = TeXt String
      deriving (Show,Read,Eq)
    instance TeX TeXt where
      teX (TeXt t) = t
    
    newtype TeXmath = TeXmath String
      deriving (Show,Read,Eq)
    instance TeX TeXmath where
      teX (TeXmath t) = "$$" ++ t ++ "$$"
    

第一种方法使用起来更容易,第二种方法更容易丰富;但我想知道它们中哪一个运行速度更快,或者Haskell是否会以完全相同的方式实现它们。


2
第二个并不是类型类的真正用途,看起来你正在尝试复制面向对象编程中的类。 - Arjan
2
你不应该以那种方式关注性能,特别是对于像渲染到字符串这样的东西:它们本质上是如此缓慢,以至于类字典可能施加的任何开销都可以忽略不计。实际上,在这里你真的不应该渲染为String,而是应该渲染为Text(或LaTeX,当然)。 - leftaroundabout
我和Arjan在一起,第二个想法似乎真的不太好。例如,像这个类型的方式(githubpandoc存储库)是如何被你的teX函数在这里呈现的。 - applicative
后面的模块有点复杂,因为它涵盖了很多内容,但请注意,这种方法具有可扩展性,而您所设想的类没有:您如何引入一个函数 html :: t -> Stringmarkdown :: t -> String,以及在该包中定义的其他类似函数? - applicative
1个回答

5
第一种方法更节省空间。调用类型类中定义的函数相当于在面向对象语言中调用方法:对于任何在类型TeX t上多态的函数(即,类型签名中有TeX t =>),都必须携带额外的隐式参数,即存储给定TeX实例的特定方法的字典。
现在,关于更快?我想对于内存占用小的程序,第一种方法由于少了一次内存分配和一次实际调用teX函数的间接引用,所以可能稍微更快一些。对于内存分配较重的程序,情况也是如此,直到程序达到某个内存分配阈值——第一个版本会稍晚达到这个阈值,因此一旦第二个版本达到该点,第一个版本会稍微更快。

7
我认为这个答案过于简化了。由于内联和类型特化,很可能TeX字典将在编译时完全解决。至于性能,我猜额外的间接寻址比分配有更大的影响。但我不会仅仅依赖直觉来判断。 - John L
1
这是正确的,但不是根本上的真理;一个人可以(应该)努力适应优化器的喜好,但我不认为这是克服使用类型类的根本开销,因为它无法可靠地保证。 - jpaugh

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