精华内容
下载资源
问答
  • 完整的common lisp的学习集合整理如下: https://github.com/GreyZhang/g_lisp 曾在网络上的文章中看到,说lisp能够提供较为完美的函数式编程体验。我还不是很熟悉什么叫做函数式编程,难道是所有的语言元素都...

             完整的common lisp的学习集合整理如下:

             https://github.com/GreyZhang/g_lisp

             曾在网络上的文章中看到,说lisp能够提供较为完美的函数式编程体验。我还不是很熟悉什么叫做函数式编程,难道是所有的语言元素都能够理解为函数还是?或许我理解的片面也不对,但是从现在学习到的很多东西中能够看得出这一点。比如,之前学习的if分支,其实if在emacs lisp就是作为一个函数来处理的。当然,很多函数在我读common lisp的时候被表述为宏,两者究竟有什么差异呢?或许,我得需要很长的时间才能够弄明白。

             继续看之前学习的配置文件:

             还是这一段,但是这次我们关注not。

             接下来,学习小结一下emacs lisp中的取反操作。前面学习了if,这个操作在C语言中算是一个较为简单的语言元素,称之为操作符。但是在emacs lisp中,这个行为看上去是一个函数。而帮助查找的方式,也是可以通过查找函数帮助的方式来找到相应的帮助信息。Emacs lisp中取反功能为not,行为跟if的使用还是很相似的,看上去都是像一个函数的调用。但是,从函数的帮助中却搜索不到。于是,我查看了一下elisp的官方文档,找到了信息如下:

             从官方手册中得知,这几个操作被称为“意向?”,或许跟函数或者宏还是有一点点差异。继续往下看的话,这三个操作还是有所不同的,其中not可以认为是一个函数,另外两个则是语言中的特殊形式。

             接下来,做一部分测试:

             这个是需要注意的,不同意C语言时候的经验,看起来0不代表false。

             至于为什么有这样的结果,官方的文档中写的还是很明确的。

             只有传入的参数是nil的时候,返回t,其他时候全都是返回nil。

             接下来测试and:

             看上去,结果似乎也有点出人意料。看一下文档就可以知道:进行and操作的时候,将会逐个元素检查,如果其中的一个为nil则返回nil,后面的不再进行检查;如果全都不是nil,则最后的数值会作为返回值。这么看的话,似乎这个功能可以理解为:查找后面的元素中是否不包含nil。

             关于or的测试:

             测试完了and,再看这个功能就不会觉得有什么意外了。Or的功能应该是逐个检查元素是否为nil,全都不是的时候返回t,否则返回第一个非nil的数值并且停止继续检查。

             功能理解清楚还是很容易的,但是这部分表达能够在后期的代码构建中运用熟练或许还是需要花点时间练习一下的。

    其他的lisp相关的学习笔记汇总,可以参考如下链接:

             https://github.com/GreyZhang/g_lisp

    展开全文
  • LISP

    千次阅读 2015-05-25 19:18:14
    Lisp,最初被拼为LISP,一个历史悠久的电脑编程语言家族。最早由约翰·麦卡锡在1958年基于λ演算创造,演化至今,是历史第二悠久的高级语言,仅次于Fortran,也是第一个函数式编程语言。 其名称源自列表处理器...

    Lisp,最初被拼为LISP,一个历史悠久的电脑编程语言家族。最早由约翰·麦卡锡在1958年基于λ演算创造,演化至今,是历史第二悠久的高级语言,仅次于Fortran,也是第一个函数式编程语言

    其名称源自列表处理器英语List Processor)的缩写。LISP有很多种方言,各个实现中的语言不完全一样。LISP语言的主要现代版本包括Common LispSchemeRacket以及Clojure。1980年代盖伊·史提尔二世编写了Common Lisp试图进行标准化,这个标准被大多数解释器和编译器所接受。还有一种是编辑器Emacs所派生出来的Emacs Lisp(而Emacs正是用Lisp作为扩展语言进行功能扩展)非常流行,并创建了自己的标准。

    历史

    1955年至1956年间,信息处理语言被创造出来,用于人工智能处理(早期的基于符号处理的人工智能领域,以图灵测试为目标)。此领域中有研究者持有观点:“符号演算系统可以派生出智能。”[1])。它首先使用了列表 (抽象数据类型)递归

    1958年,约翰·麦卡锡麻省理工学院发明了Lisp这个编程语言,采用了信息处理语言的特征。1960年,他在《ACM通讯》发表论文,名为《递归函数的符号表达式以及由机器运算的方式,第一部》(Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I)。在这篇论文中,他展示了,只要通过一些简单的运算符,以及用于函数的记号,就可以创建一个具图灵完备性语言,可用于算法中。

    麦卡锡最初使用M表示式(M-expression)写成代码,之后再转译成S表示式,举例来说,M表示式的函数语法,car[cons[A,B]],等同于S表示式(car (cons A B))。然而由于S表示式具备同像性的特性(homoiconic,即程序与数据由同样的结构存储),实际应用中一般只使用S表示式。此外,他也由借用了信息处理语言中的许多概念。

    约翰·麦卡锡的学生史帝芬·罗素在阅读完此论文后,认为Lisp编程语言当中的eval函数可以用机器码来实做。他在IBM 704机器上,写出了第一个LISP解释器。1962年,蒂姆·哈特(Tim Hart)与麦克·莱文(Mike Levin)在麻省理工学院,以Lisp语言,实做出第一个完整的lisp编译器。

    基本介绍

    LISP是第一个函数式程序语言,区别于C语言Fortran等命令型程序语言和JavaC#Objective-C等面向对象程序语言。

    由于历史的原因,Lisp长期以来被认为主要用于人工智能领域,但Lisp并不是只为人工智能而设计,而是一种通用的程序语言。

    Lisp的表达式是一个原子(atom)或表(list),原子(atom)又包含符号(symbol)与数值(number);表是由零个或多个表达式组成的序列,表达式之间用空格分隔开,放入一对括号中,如:

    abc
    ()
    (abc xyz)
    (a b (c) d)
    

    最后一个表是由四个元素构成的,其中第三个元素本身也是一个表,这种list又称为嵌套表(nested list)。

    正如算数表达式1+1有值2一样,Lisp中的表达式也有值,如果表达式e得出值v,我们说e返回v。如果一个表达式是一个表,那么我们把表中的第一个元素叫做操作符,其余的元素叫做自变量。

    Lisp的7个公理(基本操作符)

    基本操作符1 quote

    (quote x)返回x,我们简记为'x

    (quote a)
    

    上面的表达式的值是a。如果使用C语言或者Java语言的表达方式,可以说成:上面这段代码返回的值是a。

    'a
    

    这个表达式和上面的那个相同,值也是a。将quote写成 ' 只是一种语法糖

    quote起来的单一个元素会成为symbol(例如'a)。symbol是Lisp中的一个特别概念,他在代码中看起来是个string,但并不尽然,因为symbol其实会被Lisp解释器直接指向某个存储器位置,所以当你比较'apple和'apple两个symbol是否相同时,不需要像是比较string一样一个个字元逐字比较,而是直接比较存储器位置,故速度比较快(使用eq运算符来比较,如果使用equal运算符会变成逐字比较)。当你定义一个函数,或者定义一个变量时,他们的内容其实就是指向一个symbol。

    基本操作符2 atom

    (atom x)当x是一个atom或者空的list时返回原子t,否则返回NIL。在Common Lisp中我们习惯用原子t表示真,而用空表 () 或NIL表示假。

    > (atom 'a)
    t
    > (atom '(a b c))
    NIL
    > (atom '())
    t
    

    现在我们有了第一个需要求出自变量值的操作符,让我们来看看quote操作符的作用——通过引用(quote)一个表,我们避免它被求值(eval)。一个未被引用的表达式作为自变量,atom将其视为代码,例如:

    > (atom (atom 'a))
    t
    

    这是因为(atom 'a)的结果(t)被求出,并代入(atom (atom 'a)),成为(atom t),而这个表达式的结果是t。

    反之一个被引用的表仅仅被视为表

    > (atom '(atom 'a))
    NIL
    

    引用看上去有些奇怪,因为你很难在其它语言中找到类似的概念,但正是这一特征构成了Lisp最为与众不同的特点:代码和数据使用相同的结构来表示,只用quote来区分它们。

    基本操作符3 eq

    (eq x y)当x和y指向相同的对象的时候返回t,否则返回NIL,值得注意的是在Common Lisp中,原子对象在内存中只会有一份拷贝,所以(eq 'a 'a)返回t,例如:

    >(eq 'a 'a)
    t
    >(eq 'a 'b)
    NIL
    > (eq '() '())
    t
    > (eq '(a b c) '(a b c))
    NIL
    

    基本操作符4 car

    Contents of the Address part of Register number缩写

    (car x)要求x是一个表,它返回x中的第一个元素,例如:

    > (car '(a b))
    a
    

    基本操作符5 cdr

    (cdr x)同样要求x是一个表,它返回x中除第一个元素之外的所有元素组成的表,例如:

    > (cdr '(a b c))
    (b c)
    

    基本操作符6 cons

    (cons x y)返回一个cons cell(x y),如果y不是一个list,将会以dotted pair形式展现这个cons cell,例如:

    >(cons 'a 'b)
    (a . b)
    

    一个cons cell的第二项如果是另一个cons cell,就表示成表的形式,例如:

     (cons 'a (cons 'b 'c))
    

    就表示成 (a b . c) 若一个cons cell第二项为空,就省略不写,例如:

     (cons 'a  (cons 'b ()))
    

    表示为 (a b) 这样,多重的cons cell就构成了表:

    > (cons 'a (cons 'b (cons 'c ())))
    (a b c)
    

    基本操作符7 cond

    (cond (p1 e1) ...(pn en))的求值规则如下.对“条件表达式p”依次求值直到有一个返回t.如果能找到这样的p表达式,相应的“结果表达式e”的值作为整个cond表达式的返回值.

    > (cond ((eq 'a 'b) 'first)  ((atom 'a)  'second))
     second
    

    函数

    七个原始操作符中,除了quote与cond,其他五个原始操作符总会对其自变量求值.我们称这样的操作符为函数.

    语法和语义

    Scheme的Hello World程序

    (display "Hello, world!")
    ;; 在屏幕中打印出: Hello, world!
     
    ;; 函数定义
    (define (hello)
      (display "Hello, world!"))
     
    ;; 函数调用
    (hello)
    ;; 在屏幕中打印出: Hello, world!
    

    Common Lisp的Hello World程序

    (format t "hello, world!")
    ;; 在屏幕中打印出: hello, world!
     
    函数定义:
    (defun hello-world ()
      (format t "hello, world!"))
    调用函数:
    (hello-world)
    ;; 在屏幕中打印出: hello, world!
    ;; 并以NIL作为函数的返回值
    

    Clojure的Hello World程序

    (print "hello, world!")
    ;; 在屏幕中打印出: hello, world!
     
    ;; 函数定义:
    (defn hello-world []
      (print "hello, world!"))
    ;; 调用函数:
    (hello-world)
    ;; 在屏幕中打印出: hello, world!
    ;; 并以 nil 作为函数的返回值
    

    Lisp的宏

    Lisp的语法结构使数据与程序只是一线之隔(有quote就是数据,没quote就是程序)。由于Lisp这种“数据即程序、程序即数据”的概念,使Lisp的(Macro)变得非常有弹性:你可以定义宏,指定它应该被编译器翻译(宏展开)成什么程序,程序和数据都可以灵活地互相转换,最后展开的代码会成为整个程序的一部分。宏的实现非常倚重quote来达成。当你定义了一个宏,宏被quote的部分会先被编译器unquote,而没有quote、或已经被unquote的部分,则会先被求值。最终编译器生成的整个程序代码才是最后运行时的代码。以下以广泛使用的Emacs Lisp为示例(以下示例亦兼容Common Lisp),解释最基本的Lisp宏。

    想要创建一个list并赋予给fruit这个变量时不能这样做,因为这个list没有被quote过,会被编译器视为“程序”运行(会把"apple"这个字符串当成函数解释),而不是“数据”,因而产生错误:

    > (setq fruit ("apple" "banana" "citrus"))
    錯誤:"apple" 不是一個有效函數。
    

    但这样就正确了:

    > (setq fruit (quote ("apple" "banana" "citrus")))
    ("apple" "banana" "citrus")
    ;; 或者
    > (setq fruit '("apple" "banana" "citrus"))
    ("apple" "banana" "citrus")
    ;; 也可以用(list...)運算子,這樣一樣可以建立list。因為list本身是個函數,本來就應該被當成程式執行而不是資料,所以不會報錯:
    > (setq fruit (list "apple" "banana" "citrus"))
    ("apple" "banana" "citrus")
    

    前面有提到使用'符号这个语法糖能够代替quote,但还有另外一种符号是`,意义基本上与'相同,但被`包起来的部分可以再用来unquote;而'没有这种能力。

    也就是说被`给quote起来的部分是数据,但使用逗号“,”来unquote,令被quote的数据变回程序。(注意quote只有一个arg,所以arg要用list包起来)

    ;; 使用`來quote整個list
    > `("apple" "banana" "citrus")
    ("apple" "banana" "citrus")
     
    ;; 使用逗號,來unquote,這樣fruit這個變量會被重新求值。
    > `("apple" "banana" "citrus" ,fruit)
    ("apple" "banana" "citrus" ("apple" "banana" "citrus"))
     
    ;; 可以利用unquote的特性,定義一個函数,讓該函数根據輸入的參數回傳一個我們想要的list数据結構:
    (defun user-profile (name email mobile)
      `((name . ,name)
        (email . ,email)
        (mobile . ,mobile)))
     
    (user-profile "Richard" "rms@gnu.org" "Noooo!")
    => ((name . "Richard")
        (email . "rms@gnu.org")
        (mobile . "Noooo!"))
    

    简易宏示例

    这里定义一个宏叫做nonsense,这个宏可以方便地定义更多以nonsense为开头的新函数:

    (defmacro nonsense (function-name)
      `(defun ,(intern (concat "nonsense-" function-name)) (input) ;intern可以將string轉成symbol
         (print (concat ,function-name input))))
    ;; 解釋:
    ;; 這個宏在編譯時,`(defun  因為被quote所以不會被求值,
    ;; 但裡面的,(intern ...) 這一段從逗號開始,整個括號括起來的
    ;; s-expression部份會被求值。這時作為argument輸入的function-name
    ;; 就是在這時被插進macro中。其餘剩下的部份因為仍然在`(defun的quote
    ;; 影響之下,並不會被求值。
    ;; 現在宏展開完了,整個宏才被當成一般function執行。
     
    (nonsense "apple") ;使用我們剛剛定義的 nonsense 這個macro來定義新的f函数
    => nonsense-apple  ;成功定義出了新的函数叫做 nonsense-apple
     
    (nonsense "banana") ;再使用一次宏來定義新的函数叫做 nonsense-banana
    => nonsense-banana  ;成功定義了新的函数。
     
    (nonsense-apple " is good")		;使用剛剛定義出的新函数
    => "apple is good"
    (nonsense-banana " I love to eat")	;使用另一個剛剛定義函数
    => "banana I love to eat"
    

    注释

    参见

    Wikibooks-logo.svg
    您可以在 维基教科书中查找此百科条目的相关电子教程:

    外部链接

    展开全文
  • Lisp

    2011-09-30 14:28:55
    [size=large]1) John McCarthy's Home Page [url]... 2) Lisp之根源 [url]http://daiyuwen.freeshell.org/gb/rol/roots_of_lisp.html#foot84[/url] ...约翰麦卡锡于1960年发表了一篇...
    [size=large]1) John McCarthy's Home Page
    
    [url]http://www-formal.stanford.edu/jmc/[/url]


    2) Lisp之根源
    [url]http://daiyuwen.freeshell.org/gb/rol/roots_of_lisp.html#foot84[/url]

    约翰麦卡锡于1960年发表了一篇非凡的论文,他在这篇论文中对编程的贡献有如 欧几里德对几何的贡献.1 他向我们展示了,在只给定几个简单的操作符和一个 表示函数的记号的基础上, 如何构造出一个完整的编程语言. 麦卡锡称这种语 言为Lisp, 意为List Processing, 因为他的主要思想之一是[color=darkblue][b]用一种简单的数据结构表(list)来代表代码和数据[/b][/color].

    值得注意的是,麦卡锡所作的发现,不仅是计算机史上划时代的大事, 而且是一种 在我们这个时代编程越来越趋向的模式.我认为目前为止只有两种真正干净利落,[b] [color=darkblue]始终如一的编程模式:C语言模式和Lisp语言模式.[/color][/b]此二者就象两座高地, 在它们 中间是尤如沼泽的低地.随着计算机变得越来越强大,新开发的语言一直在坚定地 趋向于Lisp模式. 二十年来,开发新编程语言的一个流行的秘决是,取C语言的计 算模式,逐渐地往上加Lisp模式的特性,例如运行时类型和无用单元收集.

    在这篇文章中我尽可能用最简单的术语来解释约翰麦卡锡所做的发现. 关键是我 们不仅要学习某个人四十年前得出的有趣理论结果, 而且展示编程语言的发展方 向. Lisp的不同寻常之处--也就是它优质的定义--[b][color=darkblue]是它能够自己来编写自己[/color][/b] .为了理解约翰麦卡锡所表述的这个特点,我们将追溯他的步伐,并将他的数学标记 转换成能够运行的Common Lisp代码.

    3) CAR & CDR
    [url]http://www.iwriteiam.nl/HaCAR_CDR.html[/url]

    I wrote the first implimenation of a LISP interpreter on the IBM 704 at MIT in early in 1959. I hand-compiled John McCarthy's "Universal LISP Function".
    The 704 family (704, 709, 7090) had "Address" and "Decrement" fields that were 15 bits long in some of the looping instructions. There were also special load and store instructions that moved these 15-bit addresses between memory and the index regiseters ( 3 on the 704, 7 on the others )

    We had devised a representation for list structure that took advantage of these instructions.

    [b][color=darkblue]Because of an unfortunate temporary lapse of inspiration, we couldn't think of any other names for the 2 pointers in a list node than "address" and "decrement", so we called the functions CAR for "Contents of Address of Register" and CDR for "Contents of Decrement of Register".[/color][/b]

    After several months and giving a few classes in LISP, we realized that "first" and "rest" were better names, and we (John McCarthy, I and some of the rest of the AI Project) tried to get people to use them instead.

    Alas, it was too late! We couldn't make it stick at all. So we have CAR and CDR.

    As the 704 has 36 bit words, there were 6 bits in the list nodes that were not used. Our initial implimentation did not use them at all, but the first garbage collector, comissioned in the summer of 1959, used some of them as flags.

    Atoms were indicated by having the special value of all 1's in car of the first word of the property list. All 0's was NIL, the list terminator.

    We were attempting to improve on "IPL-V", (for Interpretive Processing of Lists - version 5) which ran on a 650. I believe that the 0 list terminator was used there, but I believe that the all 1's flag for atoms was original.

    Hope this is enlightening.


    After these historical blind alleys, it's interesting to think about why car and cdr still persist fifty years after McCarthy and Russell roamed the halls of MIT evangelising first and rest. Common Lisp does at least have first and rest as part of the standard. However, when I was taught Lisp in the mid-90's, I was encouraged to primarily favor the older car and cdr.[b][color=darkblue]I remember two primary reasons for this. The first was that existing code favored car and cdr, so it was important to be able to read code written in that style. The second reason was that first and rest impose a particular meaning on the fields of a cons cell that may or may not be appropriate.[/color] [/b]In the common case of a linear list, first and rest work rather well. If you call first on the list, you get the first element, if you call rest, you get the rest. In the case of a cons cell as a node of an association list, they work less well, unless, that is, you can figure out a reason why first makes sense as 'key', and rest makes sense as 'value'.


    4) Lisp的wiki
    [url]http://zh.wikipedia.org/zh-cn/LISP[/url]
    [url]http://lisp.org.cn/wiki/[/url]

    5) Lisp方言
    [url]http://www.schemers.org/[/url]
    [url]http://www.lisp.org/alu/home[/url]
    [url]http://www.gnu.org/software/gcl/[/url][/size]
    展开全文
  • 该工作台用于获取MAGMA-Lisp的源代码,MAGMA-Lisp是一种用于确定性编程的扩展Lisp解释器,由比萨大学信息学院(ISI)于19世纪70年代开发。 该工作台带有一些文件夹来支持该过程。 折叠式文件夹的用于发现提交...
  • 【译文】Lisp魔咒:对Lisp技术性吐槽 06 Nov 2012, by Mort Original Article: The Lisp Curseby Rudolf Winestock (Chinese Translation by Mort Yao) 这篇文章的标题叫“The Lisp

    转载的文章来自:http://www.soimort.org/posts/124/

    【译文】Lisp魔咒:对Lisp的非技术性吐槽 06 Nov 2012, by Mort

    Original Article: The Lisp Curseby Rudolf Winestock
    (Chinese Translation by Mort Yao)


    这篇文章的标题叫“The Lisp Curse”。

    我给它加了一个副标题,叫“对Lisp的非技术性吐槽”。

    毫无疑问,这是一篇非技术性质的文章,但是它也许比很多技术文章能更好地解释一些疑问。列举几个无聊的的命题:“为什么世界上最好的编程语言没有得到它应有的地位”“为什么自底向上支撑着我们个人计算机乃至整个网络的Unix / BSD / GNU / GTK+ / Qt / Linux / Apache / MySQL...不是用Lisp/Scheme写的”“为什么王垠批完Google批学术界却没做多少牛逼哄哄的项目或者“为什么说‘孤狼黑客’对开源软件的生态环境是有害的”……诸如此类。

    顺便说一句,我最初是在@yukihiro_matz的推上看到这篇文章的分享的。所谓的“孤狼黑客”,并不是指Matz和Van Rossum这些人——至少从Python和Ruby发布到社区的一刻起就不再是了。

    再补充一句,我相信不管是这篇文章的原作者还是翻译君本人,都没有任何对Lisp社区不敬的意思——只是就一项事实陈述和复述某种观点而已。

    好了,废话少说,以下是正文内容。


    这篇文章是另一次尝试,旨在解释Lisp语言在具备强大力量的同时、为何Lisp社区却无法重现它们在“AI之冬”之前的辉煌。毫无疑问,即便在式微之后,Lisp语言仍然是各种奇思妙想的重要来源。这一事实,加之各种Lisp实现的优异架构,还有如今在长达十年之后Lisp的复兴、显示着那些Lisp拥护者们是多么需要为自己的得意之作找到一点优越感;尽管有这一切,他们却没能成功地把Lisp的力量转换成一场压倒性的技术革新。

    在本文中,我将阐述这样一个论点:Lisp那极其强大的表达能力,实际上是如何成为它缺乏前进动力的致命诱因的。


    Lisp的力量也是它自身最危险的天敌。

    要证明这件事情,试想一个简单的思维实验:选择两种非面向对象的程序语言。你的任务,如果你愿意接受的话,就是为它们提供面向对象编程范式的支持,并且保持它们与原语言向后兼容——排除一些边界情况以外。把任意两种语言放到这个思维实验的设定当中,你会很容易发现一些语言较另一些语言更容易完成任务。这正是这个思维实验的要点。随手举个简单的例子:INTERCALPascal

    现在让我们把这个思维实验变得更有说服力些。想象一下给C和Scheme添加面向对象的支持。让Scheme支持面向对象不过是个稍微费点脑筋的家庭作业。另一方面,让C支持面向对象,你恐怕得有Bjarne Stroustrup的本事才能办到。

    这种对于解决问题所需才能和努力程度上的分歧,造成了Lisp的魔咒

    Lisp是如此强大,以至于在其他编程语言中的技术问题,到了Lisp中变成了社会问题。


    想一想Scheme的情形吧。因为让Scheme支持面向对象是如此轻而易举,许多Scheme黑客都完成过这件事情,更准确地说,是许多独立的Scheme黑客都完成过。这就导致了在20世纪90年代,这个语言的面向对象支持包像工厂量产出来的库存清单一样数不胜数。想想选择谬论就知道,没有哪一个包能够成为正式的标准。如今某些Scheme实现已经有了它们自己的面向对象功能,这还不算太坏。尽管如此,那些五花八门的由不同独立开发者开发出来的包所造成的问题,正如Olin Shivers在给Scheme Shell(scsh)写文档的时候所提到的一样。

    独立黑客们写出来的程序基本上遵循“抓痒模型”。这些程序解决了写程序的黑客们自己关心的问题,但是却未必能很好地处理对于其他人来说有用的部分功能。况且,虽说这些程序无疑可以在这个黑客自己的环境配置上运行得很好,但却不一定能移植到其他的Scheme实现、甚至不同平台上的同一Scheme实现上。文档可能会极度匮乏。从现实的角度讲,一个黑客用自己挤出来的空闲时间做出来的项目,当然也可能会因为黑客自己的现实生活问题而烂尾。正如Olin Shivers指出的那样,这些个人性质的项目更倾向于解决整个问题的百分之八十。

    Mark Tarver博士的文章,The Bipolar Lisp Programmer(双面Lisp程序员),对这种现象有一个确切的表述。他写道,这些“孤狼”式的Lisp黑客以及他们:

    ……不能把事情恰当地做完收尾。所谓的“用过就扔设计”绝对和拉屎这件事儿没什么两样(注:原文如此),而它来源于Lisp社区。Lisp允许你如此虎头蛇尾地了结一件事,而且还让你心安理得地这么去做。十年前,我有一次需要给我的Lisp程序写一个GUI。没问题,我找到了9个GUI库。麻烦在于这9个库没有一个拥有足够完整的文档,而且它们全部是bug充斥的。基本上,每个人都实现了他们自己的一套解决方案,对于他们来说能用就行。这是一种拉屎式的态度(注:原文如此);反正我做到了,我消化它了。这同样也是无须在他人帮助下即可得到的产物。


    那么再想一想C语言在上述思维实验中的情形吧。由于在C上面实现面向对象支持的困难程度,只有两个严肃的解决方案摆上了台面:C++,以及Objective-C。Objective-C在Mac上最为流行,而C++几乎统治了其他一切平台。这意味着,给定一个平台,如何让C支持面向对象的扩展几乎已经被唯一确定了。这意味着这些语言的面向对象支持将拥有完善的文档,高度集成的IDE,和兼容性良好的库,等等。

    Mark Tarver博士的文章说到这一点:

    现在与之相反,C/C++的做事方式完全不同。用镊子和胶水一步步搭建成一个东西实在太他妈困难了,所以你所做的一切都是实实在在的成就。你想要为它好好地写些文档。你会在做一个规模可观的C语言项目时候需要他人的帮助;因此你也更加容易变得社会性、学会去与他人合作。你需要做到这些,因为你需要完成某件事情。

    而全部的这些,从一个雇主的角度来讲,是非常吸引人的。十个能够相互交流、写文档与团队协作的人显然会比一个像拉翔一样自己去hack些Lisp代码的人更有用,而这种翔的替代品只能是另一坨翔,这些翔们随时都可能因为某些个人的问题、自己退出项目而丢下一个不可收拾的烂摊子。

    所以说,那些懂C的人不会去纠结“我应该用哪种面向对象系统?”相反,他们会去选择C++或者Objective-C,就像他们的同事所选择的一样,然后他们会提问“我该怎样使用面向对象的功能X?”答案很简单:“咕狗一下,你就知道。”


    真正的黑客,当然早就知道面向对象并非如它的拥趸们所宣称的那样是解决一切问题的灵丹妙药。真正的黑客已经在探寻更加高阶的概念,诸如不可变数据结构、类型推断、惰性求值、monad、arrow、模式匹配、约束编程,等等。真正的黑客也都知道,C/C++对于写大部分不需要进行任意位操作的程序来说并不合适。尽管如此,Lisp的魔咒仍然存在。

    一些沾沾自喜的Lisp发烧友,调研了当前学术界编程语言的硕果(Haskell、OCaml等等)后,发现它们所缺失的一些特性,要么就是已经在Lisp中存在、要么就是可以用Lisp很轻易地实现——并且可以改进——基于Lisp宏。他们也许是对的。

    但是太可惜了,Lisp黑客们。


    Mark Tarver博士——在上面已经两次引用过——曾经设计过一个Lisp的方言,叫做Qi。它仅仅由少于一万行的宏组成,基于Clisp运行。它实现了绝大部分Haskell和OCaml所独有的特性。从某个方面来说,Qi甚至超越了它们。举个例子说吧,Qi的类型推断引擎本身是图灵完全的。在这样的一个由天才科学家组成的杰出团队才能开发出Haskell语言的世界中,Tarver博士,他完全是一个人做出来了Qi。

    再看一眼上面这段话。仔细想想,是不是可怕极了。


    给读者的习题:假想Haskell与Common Lisp之间发生了激烈的对抗,下一步将会发生什么?

    答案:Lisp魔咒应验了。每两个或者三个Lisp黑客就会开发出一套属于自己的惰性求值、纯函数式、arrow、模式匹配、类型推断等等的实现。大部分这种项目都是孤狼式开发。因而,它们具备大部人所需要的80%功能(虽然这80%的定义会随情况不同而各异)。它们的文档通常会很差。它们无法在不同的Lisp系统上移植。有些项目可能起初信誓旦旦地会维护下去,直到开发者决定自己跑到别处赚钱去了,结果丢下一个无法收拾的烂摊子。有一些可能会在某种程度上多多少少地打败Haskell,但是它的认可度会被comp.lang.lisp新闻组里面的口水战淹没。

    故事的结局:任意一个传统的Lisp黑客的宏能够拼凑成一个文档匮乏的、不可移植的、bug充斥的80%的Haskell实现,仅仅因为Lisp是一种比Haskell表达力更加强大的语言。


    这个故事的教育意义在于,次级效应和三级效应至关重要。技术不只是影响我们解决技术问题的方式,它也影响着我们的社会行为。而社会行为会反馈并施加影响于我们最初试图解决的技术问题。

    Lisp是一个活生生的事例。Lisp是如此强大有力,它鼓励个人的、狂热的特立独行。在Lisp机器曾经盛极一时的年代,这种特立独行产生了举世瞩目的成果。但也正是同样的特立独行,阻碍了所谓“自底而上纯Lisp实现”的计算机系统的复苏;自Symbolics和LMI夭折之后,再也没有一个“Lisp操作系统”项目达到过值得令人关注的高度。

    这些次级和三级效应的一个后果是,即使Lisp是有史以来最富于表达力的编程语言,以至于理论上几乎不可能创造出比它更具表达力的语言,Lisper们将仍然有许多从其他编程语言那里学习的东西。Smalltalk程序员们教会了每个人——包括那些Lisp黑客们——多多少少一点关于面向对象的概念。Clean语言Mozart/Oz也有着一些自己的奇特之处。


    Lisp魔咒并不违背Stanislav Datskovskiy的至理名言:雇主们更喜欢可以被取代的雇员,而不是生产率最高的雇员。说得太实在了。你早该醒悟到那些管理学课程只是骗钱的把戏。然而,他这篇文章的最后几行似乎存在问题。请看:

    在“自由软件”的世界里,工业界教条仅仅是在口头上被激烈地批判,但却从未在实践中被反对过。那些“办公隔间地狱”里被唯恐避之不及的概念,同样也未曾在业余爱好者中间得到过青睐。

    在脚注中,他将Linux作为一个拒绝追求新奇想法的实例。为了例证,他将操作系统作为自己的一个论点(下面评论的1L是SB)。他并没有提到编程语言。Python和Ruby都受到了Lisp的影响。很多它们的饭表示了对Lisp的尊重,而他们的一些兴趣则促进了Lisp的复兴。公正地讲,JavaScript也曾被描述为“披着C外衣的Scheme”,尽管它诞生在那些办公隔间地狱中间。

    即便有如此大的影响力,在工业和开源界里,Lisp也仅仅只吸引了一部分程序员的一部分注意力,而这也是拜最近脚本语言的兴起所赐。那些拿着MBA学位的高富帅码农们的思维封闭并不是唯一的原因。“Lisp魔咒”本身能解释更多的事情。


    提供给Lisp的、可用的自由开发环境可以作为“Lisp魔咒”的一个例证。

    尽管说出来让人难堪,但必须得有人去做这件事情。忘掉Lisp机器吧;我们甚至还没有一个能达到算得上Smalltalk黑客小康标准的开发环境(“我总赶脚到Lisp是一个牛逼的语言,而Smalltalk是一个牛逼的环境。”——Ramon Leon如是说)。除非他们愿意付上千刀美元,否则Lisp黑客们仍然会受制于Emacs。(翻译君:比肾还贵的LispWorks,包邮哦亲,欲购从速哦)

    James Gosling,第一个在Unix上运行的Emacs的作者,恰当地指出了Emacs已经长达二十年没有任何基础上的变动。这是因为,Emacs维护者们只是不断地在这个当年由一个MIT的AI实验室的研究生做的设计上垒代码,那时Emacs项目仍然间接地从国债那里获得资助。也许Slashdot喷子会反驳说Emacs已经无所不能,它可以完成其它任何开发环境所能做的事情,而且只会完成得更好。不然那些当年曾经用过Lisp机器的也要这么说。

    那么,为什么Lisp黑客们没有把那些Smalltalk家伙们给彻底打败呢?为什么他们没有做出一个自由的开发环境,可以从某种程度上唤回Lisp机器曾经的辉煌,即使他们不能够重现出另一个Lisp机器?

    这件事没有发生的原因来自于Lisp魔咒。大量的Lisp黑客应该去协作。说得更详细些:大量成为Lisp黑客的人们应该去协作。而且他们应该学会合作去做一个新的设计、而非遵从一个从一开始就写死了的现有设计。这过程中不应该有任何来自外界的压力,例如风险资本家或者企业雇主,来干涉他们做事的方式。

    每个项目都会存在参与者的分歧,诸如意见不合、风格或哲学上的冲突。如果这些社会性的问题持续下去,任何大的项目都无法完成,这就产生了一个让它们倾向于解决的反作用力。“要么我们团结一心,要么我们都会被吊死在同一棵树上”。而Lisp的强大表达能力削弱了这个反作用力;一个人总可以着手去自搞一套。这样,刚愎自用的黑客们认为不值得去应付观点分歧带来的麻烦;因此他们要么退出了合作项目,要么就干脆不参加已有的项目、而选择自力更生从头开始。这就是Lisp魔咒。

    我们甚至可以自己去hack Emacs,为了追求个人理念中所谓的“足够好”。于是乎,Lisp诅咒差不多就变成了“坏即是好(Worse is Better)”的同义词。(翻译君:这最后一段有点不知所云。。。)


    Lisp的强大表达能力也会带来坏处。天下可没有免费的午餐。


    展开全文
  • Lisp技术性吐槽

    千次阅读 2014-10-29 22:28:03
    Original Article: The Lisp Curse by Rudolf Winestock ...我给它加了一个副标题,叫“对Lisp技术性吐槽”。 毫无疑问,这是一篇技术性质的文章,但是它也许比很多技术文章能更好地解释一些疑问。列举
  • STYLE-WARNING: redefining COMMON-LISP-USER::NOT-R in DEFUN NOT-R CL-USER> (not-r '(1 1)) T CL-USER> (not-r '(5 4 3 2 1)) NIL CL-USER> (not-r '(1 2 3 4 5)) T CL-USER> 来自 “ ITPUB博客...
  • Lisp笔记

    2018-04-23 17:01:58
    Lisp 笔记 common lisp 断断续续更新中… 形式 统一用表这种形式来表示,不论是语句还是数据 对于语句,均以函数调用形式进行(少数除外) 形式为(函数名 参数 …) 求值 正确求值 返回求值结果 ...
  • 和/传入消息的某些部分将决定如何处理其余部分 简单的例子 CL-USER> (ql:quickload :cl-lazy-parse) To load "cl-lazy-parse": Load 1 ASDF system: cl-lazy-parse ; Loading "cl-lazy-parse" [package cl-lazy...
  • Common Lisp

    千次阅读 2008-09-13 14:26:00
    Common Lisp 来自 维客 Jump to: navigation, search Common Lisp,一般缩写为 CL(不要和缩写同为CL的組合邏輯混淆),是Lisp的方言,标准由ANSI X3.226-1994定义。它是为了标准化此前众多...
  • Lisp语言:控制台输出输入

    千次阅读 2012-05-29 23:58:38
    Lisp全名是Lisp Processor,就是列表处理语言的意思,所以Lisp语言以列表为中心。正因为这个原因,很多Lisp语言的教程在简单介绍基本Lisp后就开始讨论Lisp中的列表,出现一堆令人费解的列表和无尽的括号。对于很多...
  • Lisp入门

    千次阅读 2016-03-22 19:01:56
    就像c一个圆绑定,标识符circle一个函数绑定。同圆形不同的是,没有简便的办法把这个函数完整的显示出来,所以DrRacket打印了这么一句#。 这个例子说明,函数同数字、图片一样,都可以看作某种值(即便它们不...
  • 一个库,用于编写模式以生成处理Lisp中具有数学(不)相关()化合物值的(a)音乐序列。 简单来说,cl-patterns是一个通过Lisp代码制作音乐和噪音的系统。 它在很大程度上受到的 启发, 旨在实现其中的大部分...
  • #返回一组表达式的逻辑‘’ ( or expr1 [ expr2 ] . . . ) #返回一组表达式的逻辑‘’ # 判断表达式相等语句最少需要两个参数 ( eq expr1 expr2 . . . ) #判断表达式是否相等 ( equal expr1...
  • AUTOLISP 编程大全

    热门讨论 2012-08-02 10:38:24
    2.2 写一个非LISP宏 33 2.3 书写一个简单的AutoLISP表达式 34 2.4 从宏到AutoLISP 38 2.5 写一个完整的AutoLISP例程 39 2.6 从用户获取输入 41 2.7 存储和加载AutoLISP应用程序 44 2.8 开发一个简单的...
  • JSCL JSCL是Common Lisp to Javascript编译器,可从Common ...静态和动态的本地出口,; ,。 词汇和特殊变量。 但是,缺少声明表达式,但是可以声明特殊变量。 可选参数和关键字参数 SETF的地方 配套 LOOP宏 克洛
  • Lisp语言基础

    2020-03-06 21:24:31
    Lisp Lisp是一款语法很简单,应用却很广...广义表(generalized list) 是一种线性的数据结构,是线性表的一种推广。 在广义表中,每个元素可以是一个值,即原子(atom),或者是一个子表。广义表(a,b,(c,d),e)(a,b,(c...
  • 递归: #lang racket (define (FIB X) (cond ((= X 0) 0) ((= X 1) 1) ((> X 1) (+ (FIB (- X 2)) (FIB (- X 1)))))) (FIB 15) 递归: #lang racket (define (fib n) (...
  • lisp入门

    2007-12-05 23:37:00
    今当远离,临表涕零,不知所言 ...和Lisp同时期甚至更晚出现的许多语言如Algo等如今大多已经消亡,又或者仅仅在一些特定的场合有一些微不足道的用途,到现在还广为人知的恐怕只剩下了Fortran和COBOL。但唯独Li...
  • 十个能够相互交流、写文档团队协作的人显然会比一个像拉翔一样自己去hack些Lisp代码的人更有用,而这种翔的替代品只能是另一坨翔,这些翔们随时都可能因为某些个人的问题、自己退出项目而丢下一个不可收拾的烂摊子...
  • AutoLisp学习笔记

    2019-10-27 12:01:00
    【前言】 最近发现,做CAD二次开发的,要么是计算机相关专业的,...AutoLISP语言是开发AutoCAD的主要工具,是LISP语言和AutoCAD有机结合的产物,在AutoCAD的发展及壮大过程中起到了重要的作用。CAD二次开发可以使用VB...
  • #资源达人分享计划#
  • java最难笔试题Prolog 目标中的 Common Lisp The resulting Translation of CommonLisp into Prolog who's non-special forms become special ...的临时的、正式指定的、漏洞百出的、缓慢的实现。 !0t
  • lisp 函数查阅

    2018-06-06 00:20:22
    * 赋值求值函数| 函数 | 格式 | 说明 || setq | (setq <变量1> <表达式1> [<变量2> <表达式2> ...]) | 赋值函数 || set | (set &l...
  • LISP语言(马希文)

    2012-12-14 20:57:19
    十一至十三章是lisp函数程序设计部分;十四章介绍lisp中的一些高级成分和高级应用。 马希文教授 1954 年进入北京大学数学力学系,时年15岁。毕业之年参加概率专门化,毕业时以他为主的研究小组所完成的优秀学术...
  • AutoLISP入门教程.pdf

    2014-10-15 10:14:05
    ​常​简​明​而​实​用​的​A​u​t​o​L​I​S​P​教​程! AutoLisp是AutoCad的最佳拍档。 AutoLisp是强化AutoCad最好、最直接的程序语言。 AutoLisp易学、易用,即使没有学习任何的程序语言,都能很快...
  • 完整的common lisp的学习集合整理如下: https://github.com/GreyZhang/g_lisp 继续学习emacs,继续学习lisp,继续学习emacs lisp。 在python中有一个函数叫做len,我个人使用的非常多。在elisp中也有一个类似...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 17,707
精华内容 7,082
关键字:

lisp与或非