功能编程和非功能编程

时间:2020-03-05 18:42:25  来源:igfitidea点击:

在大学的第二年,我们被"教"了Haskell,我对此几乎一无所知,甚至对函数式编程一无所知。

什么是函数式编程,为什么和/或者在什么地方我想用它代替非函数式编程?我是否认为C是一种非函数式编程语言是正确的?

解决方案

回答

也许值得在CoDe Mag上最近发布的F" 101"上查看这篇文章。

另外,达斯汀·坎贝尔(Dustin Campbell)拥有一个出色的博客,他在该博客上发表了许多有关他的F#入门历程的文章。

我希望我们觉得这些有用:)

编辑:

另外,仅补充一点,我对函数式编程的理解是,一切都是函数或者函数的参数,而不是实例/有状态的对象。.但是我可能是错的。时间! :)

回答

是的,我们认为C是一种非功能性语言是正确的。 C是一种过程语言。

回答

功能语言的一个主要功能是一流功能的概念。这个想法是,我们可以将函数作为参数传递给其他函数,然后将它们作为值返回。

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

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

函数式编程提供什么优势?由于每个组件都是完全隔离的,因此函数式编程可以减少潜在的错误编码。同样,使用递归和一流的功能还可以提供简单的正确性证明,这些证明通常反映了代码的结构。

回答

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

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

这种情况经常发生。现在,我可以用一种功能语言写

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

而且我永远不必再写一个新的,我可以继承它。但是我可以做一个比继承更好的事情,我可以在这个东西的构造函数中说

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

(其中*是一种"将此参数保持打开状态"表示法,这是一种多变的现象)

然后,本地的getOrCreate与如果我将整个内容写成一行而没有继承依赖性的情况下完全相同。

回答

如果我们正在寻找有关F#的好的文字

由Don Syme共同撰写的Fis专家。 F#的创建者。他专门研究.NET中的泛型,因此可以创建F#。

Fis是按照OCaml建模的,因此任何OCaml文本都可以很好地学习Fas。

回答

统计学家的示例代码John并未显示函数式编程,因为在进行函数式编程时,关键是该代码没有赋值(`record = somethingConstructor(t)是赋值),并且没有任何副作用( localMap.put(record)是带有副作用的语句。由于这两个约束,函数的所有操作都被其参数和返回值完全捕获。如果我们想使用C ++模拟功能语言,请按照看起来的方式来重写Statistician的代码:

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"关键字,并且if语句的行为类似于C ++的?:运算符。

而且,一切都是不可变的,因此localMap.put必须创建一个新的localMap副本并返回它,而不是像普通的C ++或者Java程序那样修改原始的localMap。根据localMap的结构,副本可以将指针重新使用到原始副本中,从而减少了必须复制的数据量。

函数式编程的一些优点包括以下事实:函数式程序更短,并且更容易修改函数式程序(因为没有要考虑的隐藏全局影响),并且更容易在函数式编程中正确设置程序。第一名。

但是,功能性程序往往运行缓慢(因为必须执行所有复制操作),并且它们往往无法与其他程序,操作系统进程或者操作系统进行良好的交互,这些程序处理内存地址(低位字节序)字节块和其他机器特定的非功能性位。非互操作性程度往往与功能纯度和类型系统的严格程度成反比。

较流行的功能语言具有非常非常严格的类型系统。在OCAML中,我们甚至不能混合使用整数和浮点运算,也不能使用相同的运算符(+用于添加整数,+。用于添加浮点数)。根据我们对类型检查器捕获某些类型的错误的能力的重视程度,这可能是优点还是缺点。

函数式语言也往往具有很大的运行时环境。 Haskell是一个例外(在编译时和运行时,GHC可执行文件几乎与C程序一样小),但是SML,Common Lisp和Scheme程序始终需要大量内存。