什么是Haskell最好的风格

时间:2017-12-21 16:08:15

标签: haskell functional-programming

得益于Erik Meijer的讲座,取得了重大进展。好看,也许是暗示。 Haskell允许使用多种方法编写相同的函数。在效率和可读性方面哪一个最好?

sqr' = \x -> x * x
sqr'' x = x * x
sqr''' = (^2)

1 个答案:

答案 0 :(得分:3)

在这两个顶级定义之间:

sqr' = \x -> x * x
sqr'' x = x * x

第二个在Haskell程序中几乎是普遍受欢迎的。搜索几乎所有现实世界的Haskell代码,你会发现第二个但很少有的第一个例子。相反,“lambda抽象”(即\x -> ...语法)最常用于定义匿名函数作为参数传递给更高阶函数。

第二种语法首选有几个原因。首先,它从字面上看更加简洁,从可读性的角度来看,包含较少的不同语法元素(即并置和=运算符,而不是并置,=\和{{ 1}})。它也很好地概括了使用多种模式定义函数的常见Haskell习语:

->

要使用lambda语法执行此操作,您需要添加一个显式factorial 0 = 1 factorial n | n > 0 = n * factorial (n-1) 构造,其中包含另一个语法元素集。

间:

case

或 - 可能是更公平的比较 - 介于:

之间
sqr'' x = x * x
sqr''' = (^2)

这更多是个人偏好的问题。许多Haskell程序员喜欢所谓的point-free语法的简洁外观,其中较大的函数是使用高阶函数和/或组合函数的链组成的,没有显式参数,例如:

sqr'''' x = x^2
sqr''' = (^2)

mostFrequentWord = head . maximumBy (comparing length) . group . sort . words 之类的定义更符合这种整体风格。

就这些形式之间含义的差异而言,它实际上有点复杂。由于不明原因与“单态限制”和“违约规则”有关,如果你采用以下模块:

sqr'''

并使用module Square where sqr' = \x -> x * x sqr'' x = x * x sqr''' = (^2) 对其进行编译,ghc -Osqr'的定义将是等效的 - 两者都专门用于sqr'''类型的操作,并且会准确生成相同的代码。 (经GHC 8.0.2测试)。相比之下,Integer仍然具有签名sqr''的多态性,这意味着它可以在任何数字类型上运行。

如果您添加顶级类型签名(无论如何都是好的做法!),如下所示:

Num a => a -> a

然后它们都生成完全相同的代码。您可以通过查看生成的“核心”(编译器在编译过程中创建的中间Haskell类语言)来自行验证:

module Square where
sqr', sqr'', sqr''' :: (Num a) => a -> a
sqr' = \x -> x * x
sqr'' x = x * x
sqr''' = (^2)

在生成的核心中,您将看到定义:

ghc -O -ddump-simpl -dsuppress-all -fforce-recomp Square.hs

看起来很奇怪,但基本上说,将适当的sqr' = \ @ a_aBC $dNum_aLW x_arx -> * $dNum_aLW x_arx x_arx 类型的*操作应用于参数Num。生成的代码有两种变体:

x_arx x_arx

表明GHC认为它们与sqr'' = sqr' sqr''' = sqr' 之间没有区别,因此不存在语义或性能差异。