函数式编程和非函数式编程

在我大学二年级的时候,我们被“教”Haskell,我对它几乎一无所知,对函数式编程更是一无所知。

什么是函数式编程? 为什么我要用它来代替非函数式编程? 我认为 C 是一种非函数式编程语言的想法是正确的吗?

31932 次浏览

可能值得查看这篇关于 F # “101”的文章最近在 CoDeMag 上发表。

同时,他在 Dustin Campbell 有个很棒的博客上发表了很多关于他的冒险的文章,来跟上 F # 的速度。

我希望这些对你有用:)

编辑:

另外,我对函数式编程的理解是,一切是一个函数或函数的参数,而不是实例/有状态对象。.但是我可能错了 F # 是我非常渴望进入但是没有时间的事情!:)

是的,你认为 C 是一种非函数式语言是正确的,C 是一种工作语言。

函数式语言的一个关键特性是第一类函数的概念。其思想是,您可以将函数作为参数传递给其他函数,并将它们作为值返回。

函数式编程涉及编写不改变状态的代码。这样做的主要原因是,对函数的连续调用将产生相同的结果。您可以用任何支持一级函数的语言编写函数代码,但是有些语言,比如 Haskell,不允许您更改状态。事实上,你根本不应该做任何副作用(比如打印文本)-这听起来可能是完全无用的。

相反,Haskell 对 IO 采用了一种不同的方法: monads。这些对象包含所需的 IO 操作,这些操作将由解释器的顶层执行。在任何其他层面上,它们只是系统中的对象。

函数式编程提供了哪些优势?函数式编程允许以较少的潜在缺陷进行编码,因为每个组件都是完全隔离的。此外,使用递归和一级函数可以简单地证明正确性,这通常反映了代码的结构。

我更喜欢使用函数式编程来节省自己的重复工作,制作一个更抽象的版本,然后使用它来代替。让我举个例子。在 Java 中,我经常创建记录结构的映射,从而编写 getOrCreate 结构。

SomeKindOfRecord<T> getOrCreate(T thing) {
if(localMap.contains(thing)) { return localMap.get(thing); }
SomeKindOfRecord<T> record = new SomeKindOfRecord<T>(thing);
localMap = localMap.put(thing, record);
return record;
}

这种情况经常发生

RT<T> getOrCreate(T thing,
Function<RT<T>> thingConstructor,
Map<T,RT<T>> localMap) {
if(localMap.contains(thing)) { return localMap.get(thing); }
RT<T> record = thingConstructor(thing);
localMap = localMap.put(thing,record);
return record;
}

我再也不用写新的了,我可以继承它。但是我可以做得比继承更好,我可以说在这个东西的构造函数中

getOrCreate = myLib.getOrCreate(*,
SomeKindOfRecord<T>.constructor(<T>),
localMap);

(其中 * 是一种“保持参数打开”的表示法,这是一种套用)

然后,本地 getOrCreate 与我在一行中写出的所有内容完全相同,没有继承依赖关系。

如果你正在寻找一个好的文本在 F #

专家 F # 由 Don Syme 合著。F # 的创造者。他在2005年研究过仿制药。NET,这样他就可以创建 F # 。

F # 是以 OCaml 为模型的,所以任何 OCaml 文本都可以帮助您学习 F # 。

统计学家约翰的示例代码没有显示函数式编程,因为当你进行函数式编程时,关键是代码没有任何赋值(record = thingConstructor(t)是一个赋值) ,它没有副作用(localMap.put(record)是一个有副作用的语句)。由于这两个约束,功能所做的一切都被它的参数和返回值完全捕获。如果你想用 C + + 模拟一种函数式语言,那么重写统计学家的代码的方式应该是:

RT getOrCreate(const T thing,
const Function<RT<T>> thingConstructor,
const Map<T,RT<T>> localMap) {
return localMap.contains(t) ?
localMap.get(t) :
localMap.put(t,thingConstructor(t));
}

作为无副作用规则的结果,每个语句都是返回值的一部分(因此 return第一) ,每个语句都是一个表达式。在实施函数式编程的语言中,return关键字是隐含的,而 如果语句的行为类似于 C + + 的 ?:操作符。

而且,一切都是不可变的,所以 localMap.put必须创建一个新的 本地地图副本并返回它,而不是像普通 C + + 或 Java 程序那样修改原来的 本地地图。根据 localMap 的结构,副本可以重用指向原始文件的指针,从而减少必须复制的数据量。

函数式编程的一些优点包括: 函数式程序更短,更容易修改函数式程序(因为没有隐藏的全局效应需要考虑) ,而且更容易在一开始就正确地编写程序。

然而,函数式程序往往运行缓慢(因为它们必须进行所有的复制) ,而且它们往往不能很好地与其他程序、操作系统进程或操作系统交互,这些程序处理内存地址、小端字节块以及其他机器特有的非功能位。不互操作程度往往与功能纯度和类型系统的严格程度成反比关系。

更流行的函数式语言有非常非常严格的类型系统。在 OCAML,你甚至不能混合使用整数和浮点数,或者使用相同的运算符(+ 是用来添加整数的,+ 。是用来添加浮动的)。这可能是一个优点,也可能是一个缺点,具体取决于您对类型检查器捕捉特定类型错误的能力的重视程度。

函数式语言也倾向于拥有非常大的运行时环境。Haskell 是个例外(在编译时和运行时,GHC 可执行文件几乎和 C 程序一样小) ,但 SML、 Common Lisp 和 Scheme 程序总是需要大量内存。

什么是函数式编程

目前常用的“函数式编程”有两种不同的定义:

较早的定义(源自 Lisp)是函数式编程是关于使用第一类函数的编程,也就是说,函数被当作任何其他值来对待,这样你可以将函数作为参数传递给其他函数,函数可以在它们的返回值中返回函数。这最终导致了高阶函数的使用,如 mapreduce(您可能听说过 mapReduce作为一个单独的操作被 Google 大量使用,并且毫不奇怪,它是一个近亲!).那个。NET 类型的 System.FuncSystem.Action使高阶函数在 C # 中可用。尽管局部套用在 C # 中是不实用的,但是接受其他函数作为参数的函数是常见的,例如 Parallel.For函数。

较年轻的定义(由 Haskell 推广)是函数式编程也是关于最小化和控制包括变异在内的副作用,即编写通过组合表达式来解决问题的程序。这通常被称为“纯函数式编程”。这是通过对称为“纯函数式数据结构”的数据结构采用截然不同的方法实现的。一个问题是,将传统的命令式算法转换为使用纯函数式数据结构通常会使性能下降10倍。Haskell 是唯一幸存下来的纯函数式编程语言,但是这些概念已经悄悄进入了主流编程,其中包含了像 Linq这样的库。NET.

我想在哪里使用它,而不是非函数式编程

到处都是。C # 中的 Lambdas 现在已经展示了主要的好处。C + + 11有 lambdas。现在没有理由不使用高阶函数了。如果您能够使用类似 F # 这样的语言,您还将受益于类型推断、自动泛化、局部套用和部分应用程序(以及许多其他语言特性!).

我认为 C 是一种非函数式编程语言的想法是正确的吗?

是的。C 是个工作语言。然而,通过使用 C 语言中的函数指针和 void *,您可以从函数式编程中获得一些好处。

我发现 什么是函数式编程?很有用

函数式编程是关于编写纯函数,关于删除 尽可能隐藏输入和输出,以便我们尽可能多的 代码只是描述了输入和 输出。

更喜欢显式的 when参数

public Program getProgramAt(TVGuide guide, int channel, Date when) {
Schedule schedule = guide.getSchedule(channel);


Program program = schedule.programAt(when);


return program;
}

结束了

public Program getCurrentProgram(TVGuide guide, int channel) {
Schedule schedule = guide.getSchedule(channel);


Program current = schedule.programAt(new Date());


return current;
}

函数式语言对副作用非常反感。副作用是复杂性,复杂性是错误,错误是魔鬼。函数式语言也可以帮助您避免副作用。