关于学习“如何思考功能性”的建议?
作为函数式语言的新手(几周前我开始接触 Erlang——我能接触到的第一种函数式语言)。
我开始编写一些小算法(例如 left_rotate_list
、bubble_sort、
merge_sort
等)。我发现自己经常迷失在诸如“我应该使用辅助列表来存储中间结果吗?”之类的决策中。以及“我应该创建一个辅助函数来执行此操作吗?”
一段时间后,我发现函数式编程(如果我所说的根本没有意义,请耐心等待)鼓励“自上而下”的设计:即,当我进行 merge_sort 时,您首先写下所有合并排序步骤,并将它们命名为单独的辅助函数;然后一一实现这些辅助函数(如果需要进一步划分这些辅助函数,请以相同的方法进行)。
这似乎有点违背OO设计,在OO设计中你可以从底层开始构建基本的数据结构,然后将数据结构和算法组装成你想要的东西。
感谢您的评论。是的,我想获得有关如何“用函数式语言思考”的建议(就像“用 Java 思考”、“用 C++ 思考”)。
As a newbie in functional languages (I started touching Erlang a couple of weeks ago -- the first functional language I could get my hands on).
I started to writing some small algorithms (such as left_rotate_list
, bubble_sort,
merge_sort
etc.). I found myself often getting lost in decisions such as "should I use a helper List for intermediate result storage?" and "should I create a helper function to do this?"
After a while, I found that functional programming (bear with me if what I am talking does not make sense at all) encourages a "top down" design: i.e., when I do merge_sort, you first write down all the merge sort steps, and name them as individual helper functions; and then you implement those helper functions one by one (and if you need to further dividing those helper functions, do it in the same approach).
This seems to contradict OO design a little, in which you can start from the bottom to build the basic data structure, and then assemble the data structure and algorithms into what you want.
Thanks for comments. Yes, I want to get advice about how to "think in functional language" (just like "thinking in Java", "thinking in C++").
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
答案是函数式编程是使用数学中定义的函数进行编程(简而言之,将值从域映射到共域的无副作用的东西)。实际上将其转化为“如何思考”是一个挥手的部分,很难详尽无遗,但我将举例说明我的一些想法:
第一个与模糊相关:“优雅的代码”。列表推导式可以呈现非常简洁的数学方程,例如函数的定义。只要看一下用 LC 实现的快速排序即可。这就是我对优雅、简洁、让所有行为变得清晰的定义。不是 Perl 代码高尔夫,您通常会简洁而神秘。
第二点是我在所有编程中日常使用的东西。将代码划分为当前状态的函数(方法、例程等),这些函数是无副作用的计算,为要采取的下一个操作提供输入(即使下一个要采取的操作是)。返回值后,将其交给执行所描述操作的例程,然后重新开始。
在我的脑海中,我将 Erlang 过程绘制为状态机图,其中每个顶点都是一个副作用,也是一个函数,其输出是从顶点中选择哪条边。函数式编程范式教会了我对副作用的高度重视。特别是在 Erlang 中,因为副作用在并发性中确实很重要,而 Erlang 使并发性变得非常可用。
同样,一些孤立的部落只有一个词来表示 3 以上的数字,或者没有词来表示“我的”/“你的”。感觉流行语言没有“这会导致副作用”这样的词语,但函数式编程有。它迫使你一直意识到这一点,这是一件好事。
An answer is that functional programming is to program using functions, as they are defined in mathematics (in short, side-effect free things that map values from the domain to the codomain). To actually translate that into "how to think" is the hand-waving part that is difficult to be exhaustive about, but I'll sample some of my thoughts:
Number one is associated with the vague: "elegant code". List comprehensions can present very succinct and mathematical-equations like definitions of functions. Just look at the quick-sort implemented with LCs. This is how I define elegance, succinct and makes all behaviours clear. Not that perl code-golf where you are most often terse and cryptic.
Number two is something that I use day to day in all programming. Divide code into functions (methods, routines, etc...) of current state that are side-effect free computations giving inputs to the next action to take (even which the next action to take is). When the value is returned, give it to a routine that performs the action that is described, then start over.
In my head I diagram an Erlang process as a state machine graph, where each vertex is a side-effect and a function whose output is which edge to chose out of the vertex. The high regard of side-effects is something the functional programming paradigm taught me. Especially in Erlang, since side-effects really matter in concurrency, and Erlang makes concurrency very available.
The same way some isolated tribes have only one word for numbers above 3, or no words for "mine"/"yours". It feels like popular languages do not have words for "this will cause a side-effect", but Functional Programming has it. It is forcing you to be aware of it all the time, and that is a good thing.
嗯,这实际上并不是“自上而下”或“自下而上”的设计。这是关于关注手头问题的“什么”,而不是“如何”。当我开始函数式编程时,我发现我一直在回忆命令式结构,比如 C 中的嵌套
for
循环。然后我很快发现,尝试将我的命令式思维转化为函数式结构非常困难。我将尝试给你一个更具体的例子。我将用 C 和 Haskell 实现一个等效的程序,并尝试在这两种情况下追踪我的思维过程。请注意,为了解释的目的,我已经明确地冗长了。C 中:
我的思维过程轨迹:
inputNumber
。 scanf() 写入。primeFlag
已声明并设置为1
。primeNumber
与从 2 到primeNumber/2
之间的每个数字。for
循环开始。声明了一个循环变量i
来检查primeNumber
。i
检查primeNumber
。当我们找到一个i
整除primeNumber
时,将primeFlag
设置为0
并break.循环体已写好。
for
循环中完成严格的检查过程后,检查primeFlag
的值并将其报告给用户。 printf() 写入。在 Haskell 中:
我的思维过程的轨迹:
空除数
。mod xy == 0
好吧,首先也是最重要的,思考“什么”,而不是“如何”。这可能需要大量练习才能习惯。另外,如果您像我一样以前是一名 C/C++ 程序员,请不要再担心内存问题了!现代语言有一个垃圾收集器,它是为您使用而编写的 - 所以甚至不要尝试就地修改变量。另一件对我个人有帮助的事情是:在程序中写下类似英语的定义,以抽象出执行繁重工作的函数。
Well, it's not about "top down" or "bottom up" design really. It's about focusing on the "what" of the problem at hand, rather than the "how". When I started off with functional programming, I found that I kept recalling imperative constructs like the nested
for
loop in C. Then I quickly found out that trying to translate my imperative thinking to functional constructs was very difficult. I'll try to give you a more concrete example. I'll implement an equivalent program in C and Haskell and attempt to trace my thought process in both cases. Note that I've been explicitly verbose for the purpose of explanation.In C:
Trace of my thought process:
inputNumber
. scanf() written.primeFlag
declared and set equal to1
.primeNumber
against every number from 2 toprimeNumber/2
.for
loop started. Declared a loop variablei
to checkprimeNumber
against.primeNumber
against eachi
. The moment we find even onei
that dividesprimeNumber
, setprimeFlag
to0
andbreak
. Loop body written.for
loop, check the value ofprimeFlag
and report it to the user. printf() written.In Haskell:
Trace of my thought process:
null divisors
.divisors
? First, let's write down a list of possible candidates. Wrote down Texas range from 2 to number/2.mod x y == 0
Ok, first and foremost, think "what", not "how". This can take a lot of practice to get used to. Also, if you were formerly a C/C++ programmer like me, stop worrying about memory! Modern languages have a garbage collector, and it's written for you to use- so don't even try to modify variables in place. Another thing that has personally helped me: write down English-like definitions in your program to abstract out the functions that do the heavy-lifting.
我不确定这是一个准确的说法。我最近一直在尝试自学函数式编程,我发现某种“自下而上”的编程风格确实对我有帮助。要使用合并排序的示例:
:)
我可能误用了这个术语,但这对我来说感觉像是自下而上的设计。函数式编程与面向对象编程不同,但在两者之间切换时,您不需要完全放弃现有的设计技术。
I'm not sure this is an accurate statement. I've been recently trying to teach myself functional programming, and I've found that a sort "bottom-up" style of programming really helps me. To use your example of merge sort:
:)
I could be misusing the term, but this feels like bottom-up design to me. Functional programming is different than object-oriented programming, but you shouldn't need to totally abandon existing design techniques when switched between the two.
我对此的建议:阅读小阴谋家。你可以在 Erlang 中关注它。这是一本好书,可以让你体会到这一点。
My advice for this: read The Little Schemer. You can follow it in Erlang. It's a good book to drill a sense of this into you.