我怎么'得到'Lisp?

时间:2009-07-09 17:56:53

标签: lisp

我看过The Nature of Lisp。我唯一能做到的就是“代码就是数据”。但是,如果没有定义这些术语的含义以及为什么它们通常被认为是分开的,我就没有得到任何见解。我对“代码就是数据”的初步反应是什么?

23 个答案:

答案 0 :(得分:54)

老式观点:'它'是带有符号表达式的交互式计算

Lisp支持各种表达式的简单表示

英语句子

(the man saw the moon)

<强>数学

(2 * x ** 3 + 4 * x ** 2 - 3 * x + 3)

<强>规则

(<- (likes Kim ?x) (likes ?x Lee) (likes ?x Kim))

以及 Lisp 本身

(mapcar (function sqr) (quote (1 2 3 4 5)))

还有很多人。

Lisp现在允许编写使用此类表达式计算

的程序
(translate (quote (the man saw the moon)) (quote german))

(solve (quote (2 * x ** 3 + 4 * x ** 2 - 3 * x + 3)) (quote (x . 3)))

(show-all (quote (<- (likes Kim ?x) (likes ?x Lee) (likes ?x Kim))))

(eval (quote (mapcar (function sqr) (quote (1 2 3 4 5)))))

交互式意味着编程是与Lisp的对话。输入表达式,Lisp计算副作用(例如输出)和值。

因此,您的编程会话就像与Lisp系统“交谈”。你可以使用它,直到得到正确的答案。

这些表达是什么?他们是某种语言的句子。它们是涡轮机的部分描述。它们是描述AMD处理器的浮点引擎的定理。它们是物理学中的计算机代数表达式。它们是电路的描述。它们是游戏中的规则。它们描述了游戏中演员的行为。它们是医疗诊断系统中的规则。

Lisp允许您将事实,规则,公式作为符号表达式写下来。它允许您编写使用这些表达式的程序。您可以计算公式的值。但是你可以同样轻松地编写从公式计算新公式的程序(符号数学:集成,派生,......)。这是Lisp为之设计的。

作为副作用,Lisp程序也表示为这样的表达式。然后还有一个Lisp程序,用于评估或编译其他Lisp程序。 所以Lisp的概念,带有符号表达式的计算,已经应用于Lisp本身。 Lisp程序是符号表达式,计算是一个Lisp表达式。

Alan Kay(Smalltalk成名)在Lisp the Maxwell's equations of programming中调用了Lisp评估的原始定义。

答案 1 :(得分:34)

编写Lisp代码。真正“获得”Lisp(或任何语言,就此而言)的唯一方法就是卷起袖子并实施其中的一些内容。像其他任何东西一样,你可以阅读你想要的一切,但是如果你想真正掌握正在发生的事情,你必须走出理论并开始使用实践。

答案 2 :(得分:23)

“获取”任何语言的方式是尝试在其中编写一些代码。

关于“数据是代码”的事情,在大多数语言中,执行的代码与处理的数据之间存在明显的分离。

例如,以下简单的类C函数:

void foo(int i){
  int j;

  if (i % 42 == 0){
    bar(i-2);
  }

  for (j = 0; j < i; ++j){
    baz();
  }
}

在编写代码时,静态确定实际控制流一次。函数bar不会改变,函数开头的if语句不会消失。这段代码不是数据,它不能被程序操纵。

所有可以操纵的是i的初始值。而另一方面,该值无法按代码的方式执行。您可以调用函数foo,但不能调用变量i。所以i是数据,但它不是代码。

Lisp没有这种区别。程序代码也是可以操作的数据。您的代码可以在运行时使用函数foo,也许可以添加另一个if语句,也许更改for循环中的条件,或者用另一个函数调用替换对baz的调用。您的所有代码都是可以检查和操作的数据,就像上面的函数可以检查和操作整数i一样。

答案 3 :(得分:14)

我强烈推荐实际使用方案的Structure and Interpretation of Computer Programs,但这是lisp的方言。通过让你做很多不同的练习,它将帮助你“获得”lisp,并继续展示lisp如此有用的一些方法。

答案 4 :(得分:9)

我认为你必须对编译器编写者有更多的同情才能理解代码是多么基本的数据。我承认,我从未参加过编译器课程,但将任何足够高级的语言转换为机器代码是一个难题,LISP在很多方面类似于这个过程的中间步骤。与C“接近金属”的方式相同,LISP接近编译器。

答案 5 :(得分:7)

这对我有用:

  1. 阅读“The Little Schemer”。这是让你在Lisp模式下思考的最短路径(减去宏)。作为奖励,它相对较短/有趣/便宜。

  2. 找一本好的书/教程来开始使用宏。我找到了“该计划”的第8章 编程语言“是Scheme的一个很好的起点。

  3. http://www.ccs.neu.edu/home/matthias/BTLS/

    http://www.scheme.com/tspl3/syntax.html

答案 6 :(得分:4)

答案 7 :(得分:4)

在Common Lisp中,“代码就是数据”归结为此。当你写作时,例如:

(add 1 2)

你的Lisp系统将解析该文本并生成一个包含三个元素的列表:符号ADD,以及数字1和2.所以现在它们就是数据。你可以用它们做任何你想做的事情,替换元素,插入其他东西等等。

有趣的是,您可以将此数据传递给编译器,因为您可以使用Lisp本身操作这些数据结构,这意味着您可以编写编写其他程序的程序。这并不像听起来那么复杂,Lispers一直使用宏来做。所以,只需要一本关于Lisp的书,然后试一试。

答案 8 :(得分:3)

好的,我会对此采取行动。我自己是Lisp的新手,刚从蟒蛇世界来到这里。我还没有经历过所有老Lispers谈论的突然启蒙时刻,但我会告诉你到目前为止我所看到的。

首先,看一下python代码的随机位:

def is_palindrome(st):
    l = len(st)/2
    return True if st[:l] == st[:-l-1:-1] else False

现在看看:

"""
def is_palindrome(st):
    l = len(st)/2
    return True if st[:l] == st[:-l-1:-1] else False
"""

作为一名程序员,你看到了什么?代码是相同的,仅供参考。

如果你像我一样,你会倾向于认为第一个是活跃的代码。它由许多句法元素组成。

第二个,尽管它有相似之处,但它是一个单一的句法项目。它是一个字符串。您作为单个实体与它进行交互。要将它作为代码处理 - 在句法边界上轻松处理它 - 你将不得不做一些解析。要执行它,您需要调用解释器。它与第一个完全不同。

因此,当我们在大多数语言中进行代码生成时,我们处理的是什么?字符串。当我使用python生成HTML或SQL时,我使用python字符串作为两种语言之间的接口。即使我用python生成python,字符串也是工具。*

没想到这只是......让你想要快乐地跳舞吗?在你正在使用的和你正在做的事情之间,总是存在这种奇怪的不匹配。我感觉第一次使用perl生成SQL。逃避的差异。格式化的差异:考虑尝试使生成的html文档看起来整洁。东西不容易重复使用。等

为了解决这个问题,我们连续创建了模板库。他们的一团糟。为什么这么多?我的猜测是他们从未完全满意。当他们开始变得足够强大时,他们就变成了怪物。当然,其中一些 - 例如蟒蛇世界中的SQLAlchemy和Genshi--是非常美丽和令人钦佩的怪物。让我们......嗯......避免提及PHP。

因为字符串在工作语言和工作语言之间形成了一个尴尬的界面,我们创建了第三种语言 - 模板 - 以避免它们。 **这也有点尴尬。

现在让我们看一段引用的Lisp代码:

'(loop for i from 1 to 8 do (print i))

你看到了什么?作为一个新的Lisp编码器,我已经发现自己将其视为一个字符串。它不是。它是非活动的Lisp代码。你正在看一堆列表和符号。在转动其中一个括号后尝试评估它。语言不会让你这样做:强制执行语法。

使用quasiquote,我们可以将自己的值变成这个非活动的Lisp代码:

`(loop for i from 1 to ,whatever do (print i))

注意鞋帮的性质:一件物品已被另一件物品所取代。我们没有将我们的值格式化为字符串。我们将其滑入代码中的一个插槽中。它整洁干净。

事实上,如果你想直接编辑代码的文本,那你就麻烦了。例如,如果要插入名称&lt; varname&gt;进入代码,你也想在同一个代码中使用&lt; varname&gt; -tmp,你可以直接使用模板字符串:&#34;%s-tmp =%s&#34 ;。你必须将名称提取到一个字符串中,重写字符串,然后再将其转换为符号,最后插入。

如果你想掌握Lisp的本质,我认为你可能会通过忽略defmacro和gensyms以及目前所有的橱窗装饰来获得更多。花一些时间探索quasiquote的潜力,包括@ thing。它非常方便。 Defmacro本身只提供了一种简单的方法来执行quasiquotes的结果。 ***

你应该注意的是,在Lisp中,已经完成了工作和工作之间的密封字符串/模板屏障。当你使用它时,你会发现你对两个不同层次的感觉 - 主动和被动 - 往往会消散。函数调用宏,这些宏调用具有函数(或宏!)的宏或函数与其参数一起传入。这是一种很大的汤 - 对新人来说有点令人震惊。也就是说,我发现宏和功能之间的区别与Lisp人说的一样无缝。大多数情况下它都没关系,但每当我在汤中徘徊时,我发现自己碰到了那个旧屏障的鬼魂 - 而且真的让我感到毛骨悚然!

我会克服它,我确定。不管。这种便利支付了恐慌。

现在那个Lisp在Lisp上工作了。在其他语言上工作怎么样?我个人还没到那里,但我想我看到了隧道尽头的灯光。你知道Lisp人如何继续关于S表达式与解析树是一回事吗?我认为这个想法是将外语解析成S表达式,在Lisp环境中以令人惊讶的舒适方式处理它们,然后将它们发送回本机代码。从理论上讲,每种语言都可以转换为S表达式,甚至是可执行的lisp代码。您没有使用第一语言和第三语言合作来生成第二语言的代码。这就是全部 - 当你正在研究它时 - Lisp,你可以用quasiquotes生成它。

看看这个(borrowed from PCL):

(define-html-macro :mp3-browser-page ((&key title (header title)) &body body)
  `(:html
     (:head
      (:title ,title)
      (:link :rel "stylesheet" :type "text/css" :href "mp3-browser.css"))
     (:body
      (standard-header)
      (when ,header (html (:h1 :class "title" ,header)))
      ,@body
      (standard-footer))))

看起来像HTML的S表达式版本,不是吗?我觉得Lisp作为自己的模板库工作得很好。

我开始怀疑python的S-expression版本。它有资格成为Lisp吗?它肯定不会是Common Lisp。也许它会更好 - 至少对python程序员来说。嘿,那么P-expressions呢?

* Python现在有一个名为AST的东西,我还没有探索过。一个人也可以使用python列表来表示其他语言。相对于Lisp,我怀疑两者都是一个黑客攻击。

** SQLAlchemy是一个例外。它将SQL直接转换为python做得很好。也就是说,它似乎付出了巨大的努力。

***从新手那里拿走它。我确定我在这里掩饰一些东西。此外,我意识到quasiquote不是生成宏代码的唯一方法。不过,这肯定是一个不错的选择。

答案 9 :(得分:2)

第一步是忘记使用所有C语言和类Pasc语言学到的所有内容。清空你的想法。这是最艰难的一步。

然后,对使用Lisp的编程进行了很好的介绍。不要试着将你看到的东西与你事先知道的东西联系起来(当你发现自己这样做时,重复步骤1)。我喜欢计算机程序的结构和解释(使用Scheme),实用的Common Lisp,人工智能编程的范例,Lisp的Casting Spels等等。一定要写出示例。也可以尝试练习,但要限制自己在那本书中学到的结构。如果您发现自己试图找到一些函数来设置变量或类似于for循环的语句,请重复步骤1,然后重新访问这些章节,以了解它是如何在Lisp中完成的。< / p>

答案 10 :(得分:2)

数据是代码是一种有趣的范例,支持将数据结构视为命令。以这种方式处理数据允许您以各种方式处理和操纵结构 - 例如遍历 - 通过评估它。此外,'数据是代码'范例消除了在许多情况下为数据结构开发自定义解析器的需要;语言解析器本身可用于解析结构。

答案 11 :(得分:2)

阅读并理解Lisp 1.5 Programmer's Manual的传奇第13页

据Alan Kay说,至少。

答案 12 :(得分:1)

一些大学计算机科学课程使用Lisp作为他们的入门课程的原因之一是,一般来说,新手可以或多或少地学习功能,程序或面向对象的编程。然而,对于那些已经在程序性陈述中思考的人来说,开始像功能性程序员一样思考而不是反过来要困难得多。

当我试图拿起Lisp时,我用“C口音”做到了。 set! amd begin是我的朋友和不断的同伴。编写Lisp代码而不编写任何功能代码是非常容易的,这不是重点。

您可能会注意到我没有回答您的问题,这是事实。我只是想让你知道,让你的思维以功能性的方式思考是非常困难的,而且从长远来看,这将是一个让你成为更强大的程序员的令人兴奋的练习。

Kampai!

P.S。此外,你终于明白“我的另一辆车是一辆CDr”保险杠贴纸。

答案 13 :(得分:1)

重要的是要看到数据是代码而代码是数据。这将提供eval / apply循环。递归也很有趣。

(此链接已损坏:

  

![评估和演示/应用] [1]

     

[1]:http://ely.ath.cx/~piranha/random_images/lolcode-eval_apply-2.jpg

答案 14 :(得分:1)

要真正理解lisp,你需要写它。

学会爱上carcdrcons。当你可以递归时不要迭代。开始编写一些简单的程序(阶乘,列表反转,字典查找),并逐步完成更复杂的程序(排序项目集,模式匹配)。

关于代码是数据和数据是代码的东西,我现在不用担心它。你最终会理解它,而且学习lisp并不重要。

答案 15 :(得分:1)

阅读On LispParadigms in Artificial Intelligence Programming。这两个都有很好的Lisp宏覆盖 - 真正使代码是数据概念真实。

此外,在编写Lisp时,请不要在递归或映射时进行迭代(学会喜欢mapcar)。

答案 16 :(得分:1)

我建议查看一些较新的Lisp变体,如ArcClojure。他们清理语法一点点,并且比Common Lisp更容易理解。 Clojure将是我的选择。它是在JVM上编写的,因此您不会遇到与SBCL等一些Lisp实现一起存在的各种平台实现和库支持的问题。

答案 17 :(得分:0)

我建议这是一种可怕的语言介绍。有比你引用的更好的地方和更好的人/文章/书籍。

你是程序员吗?用什么语言写的?

为了帮助您解决问题,更多背景信息可能会有所帮助。

答案 18 :(得分:0)

答案 19 :(得分:0)

我认为要学习任何你必须有的目标,例如一个简单的项目。

对于Lisp来说,一个好的简单项目是一个象征性的区分因素,例如

(diff 'x 'x) -> 1
(diff 'a 'x) -> 0
(diff `(+ ,xx ,yy) 'x) where xx and yy are subexpressions
 -> `(+ ,(diff xx 'x),(diff yy 'x))
etc. etc.

然后你需要一个简化器,比如

(simp `(+ ,x 0)) -> x
(simp `(* ,x 0)) -> 0
etc. etc.

所以如果你从一个数学表达式开始,你可以评估它以获得它的值,你可以评估它的衍生物来得到它的衍生物。

我希望这说明程序代码操作程序代码时会发生什么。

正如Marvin Minsky所说,计算机数学总是担心准确性和舍入错误,对吧?嗯,这是完全正确还是完全错误!

答案 20 :(得分:0)

关于整个“代码就是数据”的事情:

这不是由于“von Neumann architecture”吗?如果代码和数据位于物理上独立的存储器位置,则无法执行数据存储器中的位,而程序存储器中的位不能被解释为除CPU指令之外的任何位。

我能理解这一点吗?

答案 21 :(得分:-1)

这可能会有所帮助:http://www.defmacro.org/ramblings/fp.html(不是关于LISP,而是关于函数式编程作为范例)

答案 22 :(得分:-1)

我想到的方式是“代码就是数据”的最佳部分是功能在功能上与另一个变量没有区别。您可以编写编写代码的代码这一事实是Lisp最强大(通常被忽视)的一个特性。函数可以接受其他函数作为参数,甚至可以返回函数。

这使得一个代码的抽象级别比Java高得多。它使许多任务变得优雅和简洁,因此,使代码更易于修改,维护和阅读,或至少在理论上。

我想说真正“获得”Lisp的唯一方法就是花费大量时间使用它 - 一旦掌握了它,你会希望你拥有Lisp的一些功能编程语言。