我最近开始使用Haskell学习函数式编程,并在官方的Haskell wiki上发表了这篇文章:How to read Haskell。
该文章声称,由于简洁和抽象,短x
,xs
和f
等变量名称适合Haskell代码。从本质上讲,它声称函数式编程是一种独特的范式,其他范式的命名约定不适用。
您对此有何看法?
答案 0 :(得分:31)
在函数式编程范例中,人们通常不仅构造自上而下的抽象,还构建bottom-up。这意味着你基本上增强了主机语言。在这种情况下,我看到适当的简洁命名。 Haskell语言已经很简洁和富有表现力,所以你应该习惯它。
但是,在尝试对某个域进行建模时,即使函数体很小,我也不相信简洁的名称是好的。领域知识应该反映在命名中。
只是我的意见。
我将从Real World Haskell获取chapter 3的两个代码段。
在名为“A more controlled approach”的部分中,作者提供了一个返回列表第二个元素的函数。他们的最终版本是:
tidySecond :: [a] -> Maybe a
tidySecond (_:x:_) = Just x
tidySecond _ = Nothing
由于类型参数a
以及我们在内置类型上运行的事实,该函数是通用的,因此我们并不关心第二个元素究竟是什么。在这种情况下,我相信x
就足够了。就像在一个小数学方程式中一样。
另一方面,在名为“Introducing local variables”的部分中,他们正在编写一个示例函数,试图模拟银行域的一小部分:
lend amount balance = let reserve = 100
newBalance = balance - amount
in if balance < reserve
then Nothing
else Just newBalance
当然不建议在这里使用短变量名。我们实际上关心这些金额代表什么。
答案 1 :(得分:16)
我认为如果参数的语义在代码的上下文中是清楚的,那么你可以使用短变量名称。出于同样的原因,我经常在C#lambdas中使用它们。但是如果它不明确,你应该更明确地命名。
map :: (a->b) -> [a] -> [b]
map f [] = []
map f (x:xs) = f x : map f xs
对于没有接触过Haskell的人来说,这可能看起来像丑陋,不可维护的代码。但是大多数Haskell程序员会马上理解这一点。所以它完成了工作。
var list = new int[] { 1, 2, 3, 4, 5 };
int countEven = list.Count(n => n % 2 == 0)
在这种情况下,短变量名称似乎是合适的。
list.Aggregate(0, (total, value) => total += value);
但在这种情况下,命名变量似乎更合适,因为它并不是立即明显的聚合物正在做什么。
基本上,我相信不要过于担心会议,除非绝对有必要让人们不要搞砸。如果您对此事有任何选择,请使用您正在使用的上下文(语言,团队,代码块)中有意义的内容,并且可以被其他人在数小时,数周或数年后阅读时理解。其他任何事情都只是浪费时间的OCD。
答案 2 :(得分:8)
我认为确定范围是第一个原因。在命令式语言中,动态变量,尤其是全局变量,需要正确命名,因为它们在多个函数中使用。使用词法作用域,很清楚符号在编译时的约束条件。
不可变性在某种程度上也有助于此 - 在C / C ++ / Java等传统语言中,变量可以表示不同时间点的不同数据。因此,需要给它一个名称,让程序员知道它的功能。
就个人而言,我觉得像头等功能这样的功能使符号名称变得多余。在传统语言中,与符号的关联更容易;根据其用法,我们可以判断它是数据还是函数。
答案 3 :(得分:6)
我现在正在研究Haskell,但我不认为它的命名约定非常不同。当然,在Java中,你很难找到像xs
这样的名字。但是在一些数学函数中很容易找到像x
这样的名字,对于计数器等很容易找到i
,j
。我认为这些名称在正确的上下文中是完全合适的。 Haskell中的xs
仅适用于列表上的通用函数。在Haskell中有很多它们,所以这个名字广泛传播。 Java没有提供处理这种通用抽象的简单方法,这就是为什么列表(和列表本身)的名称通常更加具体,例如lists
或users
。
答案 4 :(得分:3)
我刚刚参加了许多关于Haskell的讨论,其中包含大量代码示例。只要代码处理x,i和f,命名就不会打扰我。然而,一旦我们进入重型列表操作等,我发现三个字母左右的名称比我更喜欢的可读性低得多。
公平地说,命名的一个重要部分遵循一系列约定,所以我假设一旦你进入术语,它会更容易一些。
幸运的是,没有什么能阻止我们使用有意义的名字,但我不同意语言本身会以某种方式使三个字母标识符对大多数人有意义。
答案 5 :(得分:3)
在罗马时,像罗马人那样做
(或者正如他们在我的城镇所说:“Donde fueres,haz lo que vieres”)
答案 6 :(得分:2)
任何有助于提高可读性的事情都是件好事 - 因此,有意义的名字在任何语言中都是一件好事。
我在许多语言中使用短变量名称,但它们保留用于在代码的整体含义中不重要的内容或在上下文中含义明确的内容。
我要小心我对Haskell名字的建议有多远
答案 7 :(得分:1)
我的Haskell练习只是平庸的水平,因此,我敢于尝试回答你问题的第二个更一般的部分:
“从本质上讲,它声称函数式编程是一种不同的范例,其他范式的命名约定不适用。”
我怀疑,答案是肯定的,但我对这种观点背后的动机只限于单一功能语言的经验。尽管如此,它可能很有趣,因为这是一个非常简约的,因此,理论上非常“纯粹”,并且是许多实用函数语言的基础。
我很高兴用combinatory logic这样的“极端”简约函数式编程语言编写实用程序是多么容易。
当然,函数式编程语言缺少可变变量,但组合逻辑“更进一步”,它甚至缺乏形式参数。它缺乏任何语法糖,它缺乏任何预定义的数据类型,甚至是布尔值或数字。所有东西都必须由组合器模仿,并追溯到 两个 基本组合器的应用程序。
尽管存在如此极端的极简主义,但仍然有一种实用的方法可以以一种整洁和愉快的方式对编组逻辑进行“编程”。我已经用模块化和可重复使用的方式在其中写了一个quine,即使对bootstrap self-interpreter也不会感到讨厌。
总而言之,我在使用这种极简主义的函数式编程语言时感受到以下特性:
需要发明许多辅助功能。在Haskell中,有很多语法糖(模式匹配,形式参数)。您可以在几行中编写相当复杂的函数。但是在组合逻辑中,可以通过单个函数在Haskell中表达的任务必须用精心选择的辅助函数替换。替换Haskell语法糖的负担是通过组合逻辑中巧妙选择的辅助函数来实现的。 至于回复您的原始问题:为这些辅助功能发明有意义和吸引人的名称是值得的 ,因为它们可以非常 强大< / em> 和 可在其他许多情境中重复使用 ,有时候in an unexpected way。
此外,一个组合逻辑的程序员不仅被迫找到一堆巧妙选择的辅助功能,而且更多,他 被迫(重新)发明全新的理论 即可。例如,for mimicking lists,程序员被迫用fold function模仿它们,基本上,他必须(重新)发明同态,深代数和类别理论概念。
我猜想,有些差异可以追溯到functional languages have a powerful "glue"。
这一事实答案 8 :(得分:1)
在Haskell中,使用变量名称比使用类型更少地传达意义。纯粹功能具有能够询问任何表达类型的优点,无论上下文如何。
答案 9 :(得分:0)
我同意这里提出的关于参数命名的许多观点但是快速的“在页面上找到”表明没有人提到Tacit programming(又名无点/无意义)。这是否更容易阅读可能是有争议的,所以这取决于你和&amp;你的团队,但绝对值得全面考虑。
没有命名参数=没有参数命名约定。