LISP到底算不算纯函数式lisp语言入门

到底什么是函数式编程,能做什么,是不是会崛起?_c++吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:261,448贴子:
到底什么是函数式编程,能做什么,是不是会崛起?收藏
票牛教你如何买到热门、便宜、真实的演出门票!
请问您知道什么是函数吗
忽悠人的东西,当它不存在把。
qsort [] = []qsort (x:xs) = qsort (filter (& x) xs) ++ [x] ++ qsort (filter (&= x) xs)装B利器……
这是比较混乱的玩意儿。列个科普提纲。什么是函数式范式?很直接难说清楚,从语言设计的风格开始好了。首先,比较被公认接受的,对于具体的语言来说,是指有一个“一等函数”(first class function)。不过函数这个概念本身就比较混乱。只能具体举例。比如,C++的函数就不是一等的,因为对象类型的值能被传参能被返回,函数类型的值就不行(会退化为函数指针)。换句话说C++的内建的“函数”是阉割的。这类函数式语言一开始以Lisp为代表,基本的理论基础是λ演算。其次,关于表达式和语句。语句一开始就是Fortran的语法。这种设计其实没有必要,因为脱离更基本的表达式语法,也没法表示计算。Lisp就没有在语法上特意区分出语句。函数式语言的语法设计习惯上不使用语句,因为具有一等函数的表达式的表达能力通常已经足够强。C这样的语言的“语句”除了表达确定的求值顺序外,也就是一种无谓地指令式风格的习惯罢了。第三,关于存储可变状态。修改状态(典型地,赋值)的程序是指令式范式的。函数式的范式通常避免无谓地修改状态。极端的情况是语义规则不提供修改状态的接口,如Haskell以及C++的模板元编程,这样的风格称为所谓的“纯函数式”。纯函数式的“函数”不具有修改值这类副作用(对于C/C++来说,读volatile对象也是副作用),所以对于确定的输入可以保证有确定的输出,且求值时函数调用可以以任意次序被整个替换——非纯函数式因为副作用顺序的不同会导致程序行为的不同。这种性质被称为引用透明性(referential transparency)。但是注意,纯函数式并不是实现引用透明的必要条件,保证内部状态的修改不影响参数和返回值的关联同样能做到。考虑到和通用需求的差异造成的困难,对于自律的用户来说,纯函数式其实没什么必要,到头来只是一种限制而已。所以说,所谓的函数式不一定指纯函数式。
国外很多大学在开设这个课程
通常的函数式语言有lisp啥的...通常被外人认为语法比较诡异...
关于纯函数式的一些问题,单独回复好了。乐天派的小耗子: 回复 幻の上帝 :有理,复用性如何呢?不同状态都得造一大堆参数?首先,搞monad之类玩意儿的出发点不是说为了描述状态所以故意要这么搞,而是因为既然变量的值不可变,有状态就自然不得不塞到参数里,通过函数调用来直接编码状态罢了。(当然,有了词法闭包以后非得要塞进参数的必要性也少了很多,不过对于原本的可变状态,这种偷懒方式不顶用。)换句话说,这也就是一种妥协。也正因为如此,我认为通用领域强调纯函数式是一种笑话:用了麻烦的吃力不讨好的方式去做本来就没什么技术含量的事。其次,纯函数(实际上只要求引用透明)自身的出发点,恰恰就是“便于组合”——“可靠”地“复用”。因为没有影响外部的副作用,先对哪个求值都无所谓,乃至不管是应用序还是正规序都没太大区别,所以可以玩的花样就多了很多。把两个“函数”合起来,它们的行为就是接口意义上的总和。在重写系统的意义上很直接。这时候就方便一些诸如惰性求值之类的东西跳出来顺便可以美其名曰“声明式”。例如:其实从一般需求上考虑,这并不见得是什么好事。但就这个例子里体现的而言,有两点值得注意:1.non-strict语义多少是必要的(比如if语句),推广成一般原则也没什么大不了的,某种意义上来看反倒能更加一致。2.反过来要求隐藏状态来体现接口的语义,经过若干层倒腾最后几乎总是导致实现和接口过于耦合。考虑到大部分指令式语言的用户都对分析问题消除隐藏状态不那么上心,强迫纯函数式风格的代码会让你少遇到恶心的逗比代码:要么代码够干净,要么根本写不出来。当然,我是有撸干净代码的自觉的,于是还是不喜欢这种自缚手脚的感觉。何况对我来说,鉴别和扔掉逗比代码并重新制造轮子的代价基本就是O(n),所以这个性质也没多少现实意义。特殊情况下也只是当DSL用了(比如TMP)。只是要干净地“组合”,非纯函数+允许UB就够了。第三,可靠和用起来方便也未必矛盾。为不同的状态制造不同的参数看起来麻烦,但有一等函数的情况下其实也就这样。唯一的区别是,状态在默认情况下被显式地编码罢了。拿C艹的TMP举例,如果你不希望到处看到一坨坨&&&&类似物,就得时刻自觉using。对撸码的来说,这在根本上没多出什么复杂性,只是习惯不习惯的问题(实现的性能另说)。再考察极端一些的例子,比如说,使用伪随机数发生器。初看起来会很麻烦,但说到底也就是利用一些语言特性编码出seed→result这种玩意儿罢了。构造中间状态?根本就不用自己动手。具体例子:至于“好处”么,除了组合起来可能方便以外,就是“清楚”(能显式地划分出哪些和输入状态相关的部分)了。这个看口味。对此我不爽的也只是作为设计者缺乏使用其它选择的自由而已。用起来才懒得管。至于真正改变外部的状态的东西,自然就不是纯函数式风格自己能编码出来的。被编码的只是你引起变化的操作序列,状态本身被隐藏起来了,而后置条件在语言之外约定(就是C艹这样允许副作用的语言在这里其实也一样)。这就是I/O的把戏。
楼主,这段代码有没有错误?***********************************************************************template &class tp&void insertSort(tp &a){int n = 100;for (int i = 1; i & i++) {temp = a[i];for (int j = i - 1; j &= 0 && a[j] & j--){a[j + 1] = a[j];}a[j + 1] =}}**********************************************************************
函数式编程就像逻辑电路,命令式编程就像以触发器为基本单位同步时序逻辑电路。命令式编程是以当前计算机体系结构为基础的。在函数式编程中,给变量赋值可以理解为生成一个新的变量放在原来的位置(触发器就是类似的做法)。有的问题采用函数式思想更容易理解,因为本身就是函数式的。有的问题采用命令式思想更容易理解,因为本身就是命令式的。
:还是有些细节问题。这里应该说的是变量表示可以修改的状态吧(所以“生成新的”很微妙)。顺便,命令式语言强调的是语句修改可变状态,这个应该都没有疑问。但是可变的状态是不是就得用“变量”这个被误会的概念表示——这种实际风格,我暂时没调查出是什么时候形成分野的,所以其实我之前说的也不完全确切。
擦    ✎﹏﹏﹏﹏        .★*★..  .*★ *. *..*   ★  ★  朱砂无泪 ★  ‘*.*' 蓝莲花开 ★    ‘★.   ★’      ‘*.. ★        ‘  ๓₯㎕[ENVELOPE] 梦一场她城下作画,描一副山水人家。     --来自助手版贴吧客户端
登录百度帐号推荐应用
为兴趣而生,贴吧更懂你。或Javascript函数式编程语言
投稿:hebedich
字体:[ ] 类型:转载 时间:
JavaScript 是近年来非常受瞩目的一门编程语言,它既支持面向对象编程,也支持函数式编程。本文专门介绍JavaScript函数式编程的特性。
函数式编程语言
函数式编程语言是那些方便于使用函数式编程范式的语言。简单来说,如果具备函数式编程所需的特征, 它就可以被称为函数式语言。在多数情况下,编程的风格实际上决定了一个程序是否是函数式的。
是什么让一个语言具有函数式特征?
函数式编程无法用C语言来实现。函数式编程也无法用Java来实现(不包括那些通过大量变通手段实现的近似函数式编程)。 这些语言不包含支持函数式编程的结构。他们是纯面向对象的、严格非函数式的语言。
同时,纯函数语言也无法使用面向对象编程,比如Scheme、Haskell以及Lisp。
然而有些语言两种模式都支持。Python是个著名的例子,不过还有别的:Ruby,Julia,以及我们最感兴趣的Javascript。 这些语言是如何支持这两种差别如此之大的设计模式呢?它们包含两种编程范式所需要的特征。 然而对于Javascript来说,函数式的特征似乎是被隐藏了。
但实际上,函数式语言所需要的比上述要多一些。到底函数式语言有什么特征呢?
一步一步地执行,并且要管理状态的变化
描述问题和和所需的数据变化以解决问题
主要的控制流
循环、条件、函数调用
函数调用和递归
主要的操作单元
结构体和类对象
函数作为一等公民的对象和数据集
函数式语言的语法必须要顾及到特定的设计模式,比如类型推断系统和匿名函数。大体上,这个语言必须实现lambda演算。 并且解释器的求值策略必须是非严格、按需调用的(也叫做延迟执行),它允许不变数据结构和非严格、惰性求值。
译注:这一段用了一些函数式编程的专业词汇。lambda演算是一套函数推演的形式化系统(听起来很晕), 它的先决条件是内部函数和匿名函数。非严格求值和惰性求值差不多一个意思,就是并非严格地按照运算规则把所有元素先计算一遍, 而是根据最终的需求只计算有用的那一部分,比如我们要取有一百个元素的数组的前三项, 那惰性求值实际只会计算出一个具有三个元素是数组,而不会先去计算那个一百个元素的数组。
当你最终掌握了函数式编程它将给你巨大的启迪。这样的经验会让你后面的程序员生涯更上一个台阶, 无论你是否真的会成为一个全职的函数式程序员。
不过我们现在不是在讨论如何去学习冥想;我们正在探讨如何去学习一个非常有用的工具,它将会让你成为一个更好的程序员。
总的来说,什么是使用函数式编程真正实际的优点呢?
更加简洁的代码
函数式编程更简洁、更简单、更小。它简化了调试、测试和维护。
例如,我们需要这样一个函数,它能将二维数组转化为一维数组。如果只用命令式的技术,我们会写成这样:
function merge2dArrayIntoOne(arrays) {
var count = arrays.
var merged = new Array(count);
var c = 0;
for (var i = 0; i & ++i) {
for (var j = 0, jlen = arrays[i]. j & ++j) {
merged[c++] = arrays[i][j];
return merged
现在使用函数式技术,可以写成这样:
merge2dArrayIntoOne2 = (arrays) -&
arrays.reduce (memo, item) -&
memo.concat item
var merge2dArrayIntoOne2 = function(arrays) {
return arrays.reduce( function(p,n){
return p.concat(n);
译注:原著中代码有误,调用reduce函数时少了第二个参数空数组,这里已经补上。
这两个函数具有同样的输入并返回相同的输出,但是函数式的例子更简洁。
函数式编程强制把大型问题拆分成解决同样问题的更小的情形,这就意味着代码会更加模块化。 模块化的程序具有更清晰的描述,更易调试,维护起来也更简单。测试也会变得更加容易, 这是由于每一个模块的代码都可以单独检测正确性。
由于其模块化的特性,函数式编程会有许多通用的辅助函数。你将会发现这里面的许多函数可以在大量不同的应用里重用。
在后面的章节里,许多最通用的函数将会被覆盖到。然而,作为一个函数式程序员,你将会不可避免地编写自己的函数库, 这些函数会被一次又一次地使用。例如一个用于在行间查找配置文件的函数,如果设计好了也可以用于查找Hash表。
耦合是程序里模块间的大量依赖。由于函数式编程遵循编写一等公民的、高阶的纯函数, 这使得它们对全局变量没有副作用而彼此完全独立,耦合极大程度上的减小了。 当然,函数会不可避免地相互依赖,但是改变一个函数不会影响其他的,只要输入和输出的一对一映射保持正确。
数学正确性
最后一点更理论一些。由于根植于lambda演算,函数式编程可以在数学上证明正确性。 这对于一些研究者来说是一个巨大的优点,他们需要用程序来证明增长率、时间复杂度以及数学正确性。
我们来看看斐波那契数列。尽管它很少用于概念性证明以外的问题,但是用它来解释这个概念非常好。 对一个斐波那契数列求值标准的办法是建立一个递归函数,像这样:
fibonnaci(n) = fibonnaci(n-2) + fibonnaci(n–1)
还需要加上一个一般情形:
return 1 when n & 2
这使得递归可以终止,并且让递归调用栈里的每一步从这里开始累加。
下面列出详细步骤
var fibonacci = function(n) {
if (n & 2) {
return fibonacci(n - 2) + fibonacci(n - 1);
console.log( fibonacci(8) );
// Output: 34
然而,在一个懒执行函数库的辅助下,可以生成一个无穷大的序列,它是通过数学方程来定义整个序列的成员的。 只有那些我们最终需要的成员最后才会被计算出来。
var fibonacci2 = Lazy.generate(function() {
var x = 1,
return function() {
var prev =
console.log(fibonacci2.length());
// Output: undefined
console.log(fibonacci2.take(12).toArray());
// Output: [1, 1, 2, 3, 5,8, 13, 21, 34, 55, 89, 144]
var fibonacci3 = Lazy.generate(function() {
var x = 1,
return function() {
var prev =
console.log(fibonacci3.take(9).reverse().first(1).toArray());
//Output: [34]
第二个例子明显更有数学的味道。它依赖Lazy.js函数库。还有一些其它这样的库,比如Sloth.js、wu.js, 这些将在第三章里面讲到。
我插几句:后面这个懒执行的例子放这似乎仅仅是来秀一下函数式编程在数学正确性上的表现。 更让人奇怪的是作者还要把具有相同内部函数的懒加载写两遍,完全没意义啊…… 我觉得各位看官知道这是个懒执就行了,不必深究。
非函数式世界中的函数式编程
函数式和非函数式编程能混合在一起吗?尽管这是第七章的主题,但是在我们进一步学习之前, 还是要弄明白一些东西。
这本书并没要想要教你如何严格地用纯函数编程来实现整个应用。这样的应用在学术界之外不太适合。 相反,这本书是要教你如何在必要的命令式代码之上使用纯函数的设计策略。
例如,你需要在一段文本中找出头四个只含有字母的单词,稚嫩一些的写法会是这样:
var words = [], count = 0;
text = myString.split(' ');
for (i=0; count & 4, i & text. i++) {
if (!text[i].match(/[0-9]/)) {
words = words.concat(text[i]);
console.log(words);
函数式编程会写成这样:
var words = [];
var words = myString.split(' ').filter(function(x){
return (! x.match(/[1-9]+/));
}).slice(0,4);
console.log(words);
如果有一个函数式编程的工具库,代码可以进一步被简化:
var words = toSequence(myString).match(/[a-zA-Z]+/).first(4);
判断一个函数是否能被写成更加函数式的方式是寻找循环和临时变量,比如前面例子里面的“words”和”count”变量。 我们通常可以用高阶函数来替换循环和临时变量,本章后面的部分将对其继续探索。
Javascript是函数式编程语言吗?
现在还有最后一个问题我们需要问问自己,Javascript是函数式语言还是非函数式语言?
Javascript可以说是世界上最流行却最没有被理解的函数式编程语言。Javascript是一个披着C外衣的函数式编程语言。 它的语法无疑和C比较像,这意味着它使用C语言的块式语法和中缀语序。并且它是现存语言中名字起得最差劲的。 你不用去想象就可以看出来有多少人会因Javascript和Java的关系而迷惑,就好像它的名字暗示了它会是什么样的东西! 但实际上它和Java的共同点非常少。不过还真有一些要把Javascript强制弄成面向对象语言的主意, 比如Dojo、ease.js这些库曾做了大量工作试图抽象Javascript以使其适合面向对象编程。 Javascript来自于90年代那个满世界都嚷嚷着面向对象的时代,我们被告知Javascript是一个面向对象语言是因为我们希望它是这样, 但实际上它不是。
它的真实身份可以追溯到它的原型:Scheme和Lisp,两个经典的函数式编程语言。Javascript一直都是一个函数式编程语言。 它的函数是头等公民,并且可以嵌套,它具有闭包和复合函数,它允许珂理化和monad。所有这些都是函数式编程的关键。 这里另外还有一些Javascript是函数式语言的原因:
• Javascript的词法包括了传递函数为参数的能力,具有类型推断系统,支持匿名函数、高阶函数、闭包等等。 这些特点对构成函数式编程的结构和行为至关重要。
• Javascript不是一个纯面向对象语言,它的多数面向对象设计模式都是通过拷贝Prototype对象来完成的, 这是一个弱面向对象编程的模型。欧洲电脑制造商协会脚本(ECMAScript)——Javascript的正式形式和标准实现 ——在4.2.1版本的规范里有如下陈述:
“Javascript不具有像C++、Smalltalk、Java那样的真正的类,但是支持创建对象的构造器。 一般来说,在基于类的面向对象语言里,状态由实例承载,方法由类承载,继承只是针对结构和行为。 在EMACScript里,状态和方法由对象来承载,结构、行为和状态都会被继承。”
• Javascript是一个解释型语言。Javascript的解释器(有时被称为“引擎”)非常类似于Scheme的解释器。 它们都是动态的,都有易于组合和传输的灵活的数据类型,都把代码求值为表达式块,处理函数的方式也类似。
也就是说,Javascript的确不是一个纯函数式语言。它缺乏惰性求值和内建的不可变数据。 这是由于大多数解释器是按名调用,而不是按需调用。Javascript由于其尾调用的处理方式也不太善于处理递归。 不过所有的这些问题都可以通过一些小的注意事项来缓和。需要无穷序列和惰性求值的非严格求值可以通过一个叫Lazy.js的库来实现。 不可变量只需要简单的通过编程技巧就可以实现,不过它不是通过依赖语言层面来限制而是需要程序员自律。 尾递归消除可以通过一个叫Trampolining的方法实现。这些问题将在第六章讲解。
关于Javascript是函数式语言还是面向对象语言还是两者皆是还是两者皆非的争论一直都很多,而且这些争论还要继续下去。
最后,函数式编程是通过巧妙的变化、组合、使用函数而实现编写简洁代码的方式。而且Javascript为实现这些提供了很好的途径。 如果你真要挖掘出Javascript全部的潜能,你必须学会如何将它作为一个函数式语言来使用。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具(183****7403)
(AlbertLee)
(λ.epi.clyce)
第三方登录:

我要回帖

更多关于 lisp语言 的文章

 

随机推荐