函数式编程只是有所不同,还是真的更难?


12

函数式编程只是有所不同,还是真的更难

假设某人以前从未学习过编程,而是接受过函数编程的培训。VS从未接触过编程的人,并且接受过命令式编程的教育。他会发现哪个更强硬?还是一样?

我的问题:说现在的问题是骆驼式输入

这样qwe_asd_zxc_rty_fgh_vbn变成qweAsdZxcRtyFghVbn

程序方式是:

  1. 沿 _
  2. 遍历数组,跳过第一项
  3. 对于每个条目,我们将首字母大写
  4. 将结果结合在一起

功能方式是:

  1. 如果找不到_回报input
  2. 切掉input第一个_(这样我们就可以得到qweasd_zxc_rty_gfh_cvb
  3. 大写的第一个字母head并与f(tail)

好吧,如果您有功能背景并且在过程编程方面有丰富的经验,我想问:确定过程方式是否需要花费更长的时间,或者确定函数方式需要更长的时间?

如果您有程序背景,但是有多年的函数式编程经验,我想问一个相同的问题:确定程序的方式会花费您更长的时间,还是找到功能的过程会花费更长的时间办法?


5
Ehrm,如果我们将map第3步用于变异循环而不是对我来说,“过程方式”对我来说似乎非常有用。第二种方法是我只会考虑标准库中是否没有拆分功能(在这种情况下,应将它与也未使用的命令式解决方案进行比较split)。
sepp2k 2011年

8
关于您的两个示例,没有任何特定的功能或过程。在我看来,您似乎是在对函数式编程的错误理解中进行推断。难怪您会得到不寻常的结果。
Rein Henrichs

我认为函数式编程并不难,只是有所不同。如果您没有编程经验,那么两者都很容易学习,但是由于某种原因,一旦您学习了命令式编程,函数式编程就会变得很困难。
dan_waterworth 2011年

1
我认为功能和过程之间的区别变得毫无意义,因为主流语言(如JavaScript,C#,Groovy)包含越来越多的功能。
user281377 2011年

2
对于那些以前没有编程经验的人来说,命令式编程要困难得多且违反直觉。像这样的表达x=x+1会炸毁一个没想到的大脑。函数式编程是很自然的,无非就是纯粹而便捷的严格数学函数。
SK-logic

Answers:


12

只是不同。函数式编程与大多数人都熟悉的数学紧密相关。整个“不可变变量”只会令必须根深蒂固的“可变”心态的程序员感到震惊。

对于新手来说,通常不能仅更改某些东西的价值就非常直观。

在我学习CS的地方,我们的第一门课程就是学习功能语言。而且所有学习过C ++或Java的人都曾为此苦苦挣扎。那些刚接触编程的人会很容易地接受它。


杰夫,您是编程新手之一,可以很容易地将其掌握吗?
Pacerier 2011年

我介于两者之间。在那之前,我曾用C ++和一些PHP进行过讨论,但还不足以真正适应命令式的思维方式。当您整体上看课时,模式很清楚。另外,这是将近十年前的事,所以不,我今天对编程不是很
陌生

不可变的变量?数学不是一种功能编程语言吗?mathematica中的变量肯定是可变的,不是吗?
user56834

20

只是不同而已

当您进行编程时,实质上是将您的推理方式转换为代码,您的思想与最终解决方案之间的距离可能被称为“认知鸿沟”。差距越大,越难弥合。

如果您来自程序背景,那么您将训练自己去进行程序思考,这样,与功能代码的差距就会缩小,反之亦然。

使编程范例在本质上比其他任何方式都更容易的唯一方法是,如果它映射到您已经知道的某些内容(例如普通语言),那么您将以更短的距离开始。

无论如何,功能和程序概念是一个非常不稳定的概念,它们往往会重叠


4

是的,许多人很难理解函数式编程(我倾向于说,尤其是那些首先接触过过程式编程的人)。

我还要说您的函数式编程示例并不是一个很好的函数式编程示例。它使用递归,只是组成一个结果而不是修改状态,但仅此而已。

为了获得更好的函数式编程示例,请考虑一个更普遍的问题:与其“搜索下划线并将下一个字母转换为大写字母”,不如将其视为搜索模式并在执行时执行一些任意代码的一种特殊情况。找到了。

许多语言都支持这一点,但是要做到这一点,它们要求我们将模式指定为类似于正则表达式的形式。但是,正则表达式只不过是一种特殊用途的编程语言,而RE实现是该语言的编译器和/或解释器。编译RE的结果基本上是一个函数(在特殊的RE虚拟机中)执行以将表达式与某些输入进行匹配。

在像Perl这样的东西中,您使用一种特殊的语言来指定模式,并使用一种特殊的编译器将该字符串转换为某种类似于函数的事物,并使用一种特殊的解释器将这种类似于函数的事物执行起来。在功能语言中,通常会使用该语言本身来指定模式,并使用该语言自己的编译器来产生一个函数。我们可以动态生成该函数(大约就像我们可以在需要时编译RE一样),但是当我们这样做时,结果可以像语言中的任何其他函数一样执行,而无需特殊的RE东西来执行。

结果是我们可以相对容易地概括上述问题。但是,与其直接将“ _”和“大写”硬编码到转换中,不如说:

s&r(pattern, transform, string) {
    if (!pattern(string))
        return string
    else
        return transform(matched part of string) + s&r(rest of string);
}

但是,与将模式指定为RE的方法不同,我们可以将模式直接指定为实函数,并仍然使用它,例如:

my_pattern(string) return beginning(string) == '_';

然后,我们将该函数传递给s&r。现在,它是一个非常简单的功能,并且我们已经完全对其进行了静态编码。当我们像可以使用RE那样使用功能性语言并基于用户输入等内容动态生成一个全新的功能时,一种功能性语言在很大程度上变得很有趣,但是与RE不同的是,该功能不需要特殊的RE解释器即可运行-就像其他任何正常功能一样。


4

这是Racket中的完整代码:

;; camelize : string -> string
(define (camelize str)
  (let ([parts (regexp-split #rx"_" str)])
    ;; result of regexp-split is never empty
    (apply string-append
           (first parts)
           (map string-titlecase (rest parts)))))

(camelize "qwe_asd_zxc_rty_fgh_vbn")
;; => "qweAsdZxcRtyFghVbn"

作为具有程序经验的函数式程序员,我认为“弄清楚”一个程序解决方案不会花更长的时间,但是键入它肯定会花更长的时间。

顺便说一句,原始帖子中的示例预期结果是错误的:它在末尾缺少“ h”。


gd指出了这一点。编辑
Pacerier,2011年

3

我的理论是编程模型越接近计算机的实际工作,就越容易理解。指针很难理解,除非您意识到它们本质上是机器地址。在您有意识地逐步执行一个小示例,看到堆栈框架并意识到将相同变量的不同值存储在何处之前,很难理解递归。这并不意味着汇编程序编程要比高级编程更容易,但是看到了它的完成方式后,无论是在编程方面还是在通用性方面,对于精通技能的心智模型都产生了奇迹。

现在,过程模型更接近于通常的机器体系结构:分配是存储器(或寄存器)写入。过程调用实际上只是花哨的跳转,if实际上是有条件的跳转,等等。但是例如,在Lisp中,没有简单的低级等效词法绑定或lambda表达式。理解它需要您想象语言层和物理机之间完全独立的抽象功能机,因为显然大多数人都做不到。

(我熟悉冯·诺依曼体系结构最终是任意的想法,我们不应该以机器体系结构这样无关的细节来损害初学者的思想,而应该将它们直接引入编程语言的语义中。实际上,我已经我自己教过一些这样的课程。但是,我越来越感到这是一个崇高而又被误导的目标;人们通过从下而上的理解来学习编程,而函数式编程的方式则更长。


7
按照这种逻辑,汇编程序应该是所有语言中最容易学习的方法:)
洪德2011年

4
如果您从正确的方向进行编程,那么函数式编程非常容易理解。您提到的“抽象功能机器”就是代数。通过术语重写进行评估;功能应用是通过替换完成的。程序员学习使用与多年数学案例中已经看到的相同的工具来解决问题。如果他们追求CS,那么有足够的时间以后再见一堆乌龟。如果不是,他们仍然学习了有用的解决问题的技能和设计原则。看一看如何设计程序
Ryan Culpepper

2
@mko不,按照这种逻辑,实际的字节码011011001001101...将是最容易学习的语言!
MarkJ 2011年

2
@konrad:RISC汇编程序可能是最容易学习的语言。要知道如何使它发挥作用,是另外一个故事……
Bryan Boettcher
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.