[英]What's the best style in Haskell
Made serious progress also thanks to Erik Meijer's lectures. 感谢Erik Meijer的演讲,也取得了重大进展。 Good watch, maybe a hint.
好手表,也许暗示。 Haskell allows for several ways to write the same function.
Haskell允许使用几种方法来编写相同的函数。 Which one of these would be best in terms of efficiency and readability?
就效率和可读性而言,哪一个最好?
sqr' = \x -> x * x
sqr'' x = x * x
sqr''' = (^2)
Between these two top-level definitions: 在这两个顶级定义之间:
sqr' = \x -> x * x
sqr'' x = x * x
the second is pretty much universally preferred in Haskell programs. 第二个在Haskell程序中几乎是普遍首选的。 Search through almost any chunk of real-world Haskell code, and you will find many examples of the second but few of the first.
搜索几乎所有现实世界中的Haskell代码块,您会发现第二个示例很多,但第一个示例很少。 Instead, "lambda abstraction" (ie, the
\\x -> ...
syntax) is most often used for defining anonymous functions to pass as arguments to higher order functions. 相反,“ lambda抽象”(即
\\x -> ...
语法)最常用于定义匿名函数,以将其作为参数传递给高阶函数。
There are a couple of reasons the second syntax is preferred. 选择第二种语法有两个原因。 First, it's literally more concise and, from a readability perspective, incorporates fewer distinct syntactic elements (ie, juxtaposition and the
=
operator, instead of juxtaposition, =
, \\
, and ->
). 首先,从字面上看,它更加简洁,从可读性的角度来看,它包含更少的不同语法元素(即并置和
=
运算符,而不是并置=
, \\
和->
)。 It also generalizes well to the common Haskell idiom of defining a function using multiple patterns: 它还很好地概括了使用多个模式定义函数的常见Haskell习惯用法:
factorial 0 = 1
factorial n | n > 0 = n * factorial (n-1)
To do this with the lambda syntax, you'd need to add an explicit case
construct, involving yet another set of syntactic elements. 要使用lambda语法执行此操作,您需要添加一个显式的
case
构造,其中涉及另一套语法元素。
Between: 之间:
sqr'' x = x * x
sqr''' = (^2)
or -- perhaps a fairer comparison -- between: 或者-也许是更公平的比较:
sqr'''' x = x^2
sqr''' = (^2)
it's more a matter of personal preference. 这更多是个人喜好问题。 Many Haskell programmers like the clean look of so-called point-free syntax, where larger functions are made up using higher-order functions and/or chains of composed functions without explicit arguments, like:
许多Haskell程序员喜欢所谓的无点语法的外观,其中较大的函数是使用高阶函数和/或没有明确参数的组合函数链组成的,例如:
mostFrequentWord
= head . maximumBy (comparing length) . group . sort . words
and definitions like sqr'''
are more in line with this overall style. 和
sqr'''
类的定义更符合这种总体风格。
In terms of differences in meaning between these forms, it's actually a little complicated. 就这些形式之间的含义差异而言,实际上有点复杂。 For obscure reasons having to do with things called "the monomorphism restriction" and "defaulting rules", if you took the following module:
如果您采用以下模块,则出于晦涩的原因,它们与称为“单态性限制”和“默认规则”的事情有关:
module Square where
sqr' = \x -> x * x
sqr'' x = x * x
sqr''' = (^2)
and compiled it with ghc -O
, the definitions of sqr'
and sqr'''
would be equivalent -- both would be specialized to operate on the Integer
type and would generate exactly the same code. 并用
ghc -O
编译, sqr'
和sqr'''
的定义是等效的-两者都将专门用于Integer
类型,并且将生成完全相同的代码。 (Tested with GHC 8.0.2). (使用GHC 8.0.2测试)。 In contrast,
sqr''
remains polymorphic with signature Num a => a -> a
, meaning it can operate on any numeric type. 相反,
sqr''
保持多态性并带有签名Num a => a -> a
sqr''
Num a => a -> a
,这意味着它可以对任何数字类型进行操作。
If you add top-level type signatures (good practice anyway!), like so: 如果添加顶级类型签名(无论如何,都是好的做法!),如下所示:
module Square where
sqr', sqr'', sqr''' :: (Num a) => a -> a
sqr' = \x -> x * x
sqr'' x = x * x
sqr''' = (^2)
then they all generate exactly the same code. 然后它们都生成完全相同的代码。 You can verify this yourself by peeking at the generated "core" (the intermediate Haskell-like language that the compiler creates as a midpoint in the compilation process) using:
您可以使用以下方法查看生成的“核心”(编译器在编译过程中创建的中间点,类似于Haskell的中间语言),从而自己验证这一点:
ghc -O -ddump-simpl -dsuppress-all -fforce-recomp Square.hs
In the generated core, you'll see the definition: 在生成的核心中,您将看到定义:
sqr' = \ @ a_aBC $dNum_aLW x_arx -> * $dNum_aLW x_arx x_arx
which looks weird, but basically says, apply the *
operation for the appropriate Num
type to the arguments x_arx x_arx
. 看起来很奇怪,但从根本上说,将适当的
Num
类型的*
操作应用于参数x_arx x_arx
。 The generated code for the two variants: 为两个变体生成的代码:
sqr'' = sqr'
sqr''' = sqr'
shows that GHC sees no difference between them and sqr'
, and so there will be no semantic or performance difference. 表明GHC认为它们和
sqr'
之间没有区别,因此在语义或性能上也没有区别。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.