函数式编程是否需要新的命名约定?
我最近开始使用 Haskell 学习函数式编程,并在官方 Haskell wiki 上看到这篇文章:如何阅读哈斯克尔。
该文章声称,诸如 x
、xs
和 f
之类的短变量名称由于简洁和抽象而适合 Haskell 代码。从本质上讲,它声称函数式编程是一种独特的范式,因此其他范式的命名约定不适用。
您对此有何看法?
I recently started studying functional programming using Haskell and came upon this article on the official Haskell wiki: How to read Haskell.
The article claims that short variable names such as x
, xs
, and f
are fitting for Haskell code, because of conciseness and abstraction. In essence, it claims that functional programming is such a distinct paradigm that the naming conventions from other paradigms don't apply.
What are your thoughts on this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
在函数式编程范式中,人们通常不仅自上而下构建抽象,而且 自下而上。这意味着您基本上增强了宿主语言。在这种情况下,我认为简洁的命名是合适的。 Haskell 语言已经简洁且富有表现力,所以您应该习惯它。
然而,当尝试对某个域进行建模时,我不认为简洁的名称是好的,即使函数体很小。领域知识应该体现在命名中。
只是我的意见。
为了回应您的评论,
我将从 Real World Haskell 中获取两个代码片段,均来自 第 3 章。
在名为“更受控制的方法的部分中”,作者提出了一个返回列表第二个元素的函数。他们的最终版本是这样的:
由于类型参数
a
以及我们正在处理内置类型的事实,该函数足够通用,因此我们并不真正关心第二个元素是什么实际上是。我相信在这种情况下x
就足够了。就像一个小数学方程一样。另一方面,在名为“引入局部变量的部分中”,他们正在编写一个示例函数,尝试对银行领域的一小部分进行建模:
当然不建议在此处使用短变量名称。我们实际上确实关心这些金额代表什么。
In a functional programming paradigm, people usually construct abstractions not only top-down, but also bottom-up. That means you basically enhance the host language. In this kind of situations I see terse naming as appropriate. The Haskell language is already terse and expressive, so you should be kind of used to it.
However, when trying to model a certain domain, I don't believe succinct names are good, even when the function bodies are small. Domain knowledge should reflect in naming.
Just my opinion.
In response to your comment
I'll take two code snippets from Real World Haskell, both from chapter 3.
In the section named "A more controlled approach", the authors present a function that returns the second element of a list. Their final version is this:
The function is generic enough, due to the type parameter
a
and the fact we're acting on a built in type, so that we don't really care what the second element actually is. I believex
is enough in this case. Just like in a little mathematical equation.On the other hand, in the section named "Introducing local variables", they're writing an example function that tries to model a small piece of the banking domain:
Using short variable name here is certainly not recommended. We actually do care what those amounts represent.
我认为如果参数的语义在代码的上下文中是清晰的,那么您就可以摆脱短变量名的困扰。出于同样的原因,我经常在 C# lambda 中使用它们。然而,如果它不明确,你应该更明确地命名。
对于没有接触过 Haskell 的人来说,这可能看起来是丑陋的、难以维护的代码。但大多数 Haskell 程序员会立即理解这一点。这样就完成了工作。
在这种情况下,短变量名似乎是合适的。
但在这种情况下,命名变量似乎更合适,因为聚合正在做什么并不能立即显现出来。
基本上,我认为不必太担心惯例,除非绝对有必要防止人们搞砸。如果您在这件事上有任何选择,请使用在您正在工作的上下文(语言、团队、代码块)中有意义的内容,并且其他人在数小时、数周或数年后阅读它时也能理解。其他任何事情都只是浪费时间的强迫症。
I think if the semantics of the arguments are clear within the context of the code then you can get away with short variable names. I often use these in C# lambdas for the same reason. However if it is ambiguous, you should be more explicit with naming.
To someone who hasn't had any exposure to Haskell, that might seem like ugly, unmaintainable code. But most Haskell programmers will understand this right away. So it gets the job done.
In that case, short variable name seems appropriate.
But in this case it seems more appropriate to name the variables, because it isn't immediately apparent what the Aggregate is doing.
Basically, I believe not to worry too much about convention unless it's absolutely necessary to keep people from screwing up. If you have any choice in the matter, use what makes sense in the context (language, team, block of code) you are working, and will be understandable by someone else reading it hours, weeks or years later. Anything else is just time-wasting OCD.
我认为范围界定是造成这种情况的第一大原因。在命令式语言中,动态变量,尤其是全局变量需要正确命名,因为它们在多个函数中使用。通过词法作用域,可以清楚地了解符号在编译时绑定的内容。
不变性也在一定程度上促成了这一点——在 C/C++/Java 等传统语言中,变量可以表示不同时间点的不同数据。因此,需要给它一个名称,以便程序员了解其功能。
就我个人而言,我认为像一流函数这样的功能使符号名称变得相当多余。在传统语言中,更容易与符号联系起来。根据它的用法,我们可以判断它是数据还是函数。
I think scoping is the #1 reason for this. In imperative languages, dynamic variables, especially global ones need to be named properly, as they're used in several functions. With lexical scoping, it's clear what the symbol is bound to at compile time.
Immutability also contributes to this to some extent- in traditional languages like C/ C++/ Java, a variable can represent different data at different points in time. Therefore, it needs to be given a name to give the programmer an idea of its functionality.
Personally, I feel that features features like first-class functions make symbol names pretty redundant. In traditional languages, it's easier to relate to a symbol; based on its usage, we can tell if it's data or a function.
我现在正在研究Haskell,但我不觉得它的命名约定有那么大的不同。当然,在 Java 中你很难找到像
xs
这样的名字。但是在一些数学函数中很容易找到像x
这样的名称,在计数器等中找到i
、j
等名称。我认为这样的名称是非常合适的在正确的背景下。 Haskell 中的xs
仅适用于列表上的泛型函数。 Haskell 中有很多这样的名字,所以这个名字很广泛。 Java 没有提供简单的方法来处理此类通用抽象,这就是为什么列表(以及列表本身)的名称通常更加具体,例如lists
或users
。I'm studying Haskell now, but I don't feel that its naming conventions is so very different. Of course, in Java you're hardly to find a names like
xs
. But it is easy to find names likex
in some mathematical functions,i
,j
for counters etc. I consider such names to be perfectly appropriate in right context.xs
in Haskell is appropriate only generic functions over lists. There's a lot of them in Haskell, so this name is wide-spread. Java doesn't provide easy way to handle such a generic abstractions, that's why names for lists (and lists themselves) are usually much more specific, e.g.lists
orusers
.我刚刚参加了一些关于 Haskell 的讲座,其中有很多代码示例。只要代码处理 x、i 和 f,命名就不会困扰我。然而,一旦我们开始进行繁重的列表操作等工作,我就发现这三个字母左右的名称的可读性比我喜欢的要差得多。
公平地说,命名的一个重要部分遵循了一组约定,所以我认为一旦您了解了术语,就会容易一些。
幸运的是,没有什么可以阻止我们使用有意义的名称,但我不同意语言本身以某种方式使三个字母标识符对大多数人有意义。
I just attended a number of talks on Haskell with lots of code samples. As longs as the code dealt with x, i and f the naming didn't bother me. However, as soon as we got into heavy duty list manipulation and the like I found the three letters or so names to be a lot less readable than I prefer.
To be fair a significant part of the naming followed a set of conventions, so I assume that once you get into the lingo it will be a little easier.
Fortunately, nothing prevents us from using meaningful names, but I don't agree that the language itself somehow makes three letter identifiers meaningful to the majority of people.
在罗马时,入乡随俗
(或者正如我镇上的人所说:“Donde fueres, haz lo que vieres”)
When in Rome, do as the Romans do
(Or as they say in my town: "Donde fueres, haz lo que vieres")
任何有助于可读性的东西都是好事 - 因此,有意义的名称在任何语言中都是好事。
我在许多语言中使用短变量名,但它们是为代码整体含义不重要或上下文中含义明确的内容保留的。
我会小心我对 Haskell 名称的建议采取了多大程度
Anything that aids readability is a good thing - meaningful names are therefore a good thing in any language.
I use short variable names in many languages but they're reserved for things that aren't important in the overall meaning of the code or where the meaning is clear in the context.
I'd be careful how far I took the advice about Haskell names
我的 Haskell 实践只是中等水平,因此,我敢于尝试仅回答您问题的第二个、更一般的部分:
“本质上,它声称函数式编程是一种独特的范式,以至于来自其他范式不适用。”
我怀疑答案是“是”,但我这个观点背后的动机仅限于单一功能语言的经验。不过,它可能很有趣,因为这是一种极其简约的语言,因此理论上非常“纯粹”,并且底层是许多实用的函数式语言。
我很好奇用这样一种“极其”简约的函数式编程语言(例如 组合逻辑)编写实用程序是多么容易。
当然,函数式编程语言缺乏可变变量,但组合逻辑“更进一步”,甚至缺乏形式参数。它缺乏任何语法糖,缺乏任何预定义的数据类型,甚至布尔值或数字。一切都必须由组合器模仿,并追溯到两个基本组合器的应用。
尽管有如此极端的极简主义,但仍然有一些实用的方法可以以简洁而愉快的方式“编程”组合逻辑。我已经以模块化和可重用的方式在其中编写了 quine ,并且它不会甚至对 bootstrap a 自我解释器 就可以了。
总结起来,我在使用这种极其简约的函数式编程语言时感受到了以下几个特点:
需要发明很多辅助函数。在Haskell中,有很多语法糖(模式匹配、形式参数)。您可以用几行代码编写相当复杂的函数。但在组合逻辑中,可以在 Haskell 中用单个函数表达的任务必须用精心选择的辅助函数来替换。替换 Haskell 语法糖的负担由组合逻辑中巧妙选择的辅助函数承担。 至于回答您原来的问题:为这些辅助函数军团发明有意义且朗朗上口的名称是值得的,因为它们可以非常强大< /em>并且可以在许多其他上下文中重用,有时以意想不到的方式。
此外,组合逻辑程序员不仅被迫找到一堆精心选择的辅助函数的朗朗上口的名称,而且更重要的是,他被迫(重新)发明全新的理论。例如,用于模仿列表,程序员被迫模仿它们基本上,他必须(重新)发明变形论、深层代数和范畴论概念。
我猜想,一些差异可以追溯到以下事实: 函数式语言具有强大的“粘合剂”。
My Haskell practice is only of mediocre level, thus, I dare to try to reply only the second, more general part of Your question:
"In essence, it claims that functional programming is such a distinct paradigm that the naming conventions from other paradigms don't apply."
I suspect, the answer is "yes", but my motivation behind this opinion is restricted only on experience in just one single functional language. Still, it may be interesting, because this is an extremely minimalistic one, thus, theoretically very "pure", and underlying a lot of practical functional languages.
I was curios how easy it is to write practical programs on such an "extremely" minimalistic functional programming language like combinatory logic.
Of course, functional programming languages lack mutable variables, but combinatory logic "goes further one step more" and it lacks even formal parameters. It lacks any syntactic sugar, it lacks any predefined datatypes, even booleans or numbers. Everything must be mimicked by combinators, and traced back to the applications of just two basic combinators.
Despite of such extreme minimalism, there are still practical methods for "programming" combinatory logic in a neat and pleasant way. I have written a quine in it in a modular and reusable way, and it would not be nasty even to bootstrap a self-interpreter on it.
For summary, I felt the following features in using this extremely minimalistic functional programming language:
There is a need to invent a lot of auxiliary functions. In Haskell, there is a lot of syntactic sugar (pattern matching, formal parameters). You can write quite complicated functions in few lines. But in combinatory logic, a task that could be expressed in Haskell by a single function, must be replaced with well-chosen auxiliary functions. The burden of replacing Haskell syntactic sugar is taken by cleverly chosen auxiliary functions in combinatory logic. As for replying Your original question: it is worth of inventing meaningful and catchy names for these legions of auxiliary functions, because they can be quite powerful and reusable in many further contexts, sometimes in an unexpected way.
Moreover, a programmer of combinatory logic is not only forced to find catchy names of a bunch of cleverly chosen auxiliary functions, but even more, he is forced to (re)invent whole new theories. For example, for mimicking lists, the programmer is forced to mimick them with their fold functions, basically, he has to (re)invent catamorphisms, deep algebraic and category theory concepts.
I conjecture, several differences can be traced back to the fact that functional languages have a powerful "glue".
在 Haskell 中,用变量名来表达含义比用类型来表达要少。纯函数式的优点是能够询问任何表达式的类型,而不管上下文如何。
In Haskell, meaning is conveyed less with variable names than with types. Being purely functional has the advantage of being able to ask for the type of any expression, regardless of context.
我同意这里关于参数命名的很多观点,但是快速“在页面上查找”表明没有人提到隐性编程(又名无点/无点)。这是否更容易阅读可能是有争议的,所以这取决于你和你。您的团队,但绝对值得彻底考虑。
无命名参数 = 无参数命名约定。
I agree with a lot of the points made here about argument naming but a quick 'find on page' shows that no one has mentioned Tacit programming (aka pointfree / pointless). Whether this is easier to read may be debatable so it's up to you & your team, but definitely worth a thorough consideration.
No named arguments = No argument naming conventions.