如果您想学习一些旧版Lisp的基础知识,那么Emacs Lisp就可以了。
- Emacs Lisp:可在Emacs中使用。开发环境已包含。是主流Lisp的旧方言。缺少很多概念。有许多用于编辑器编程的扩展。Common Lisp和Emacs Lisp共享一些直接的遗产(命名、概念等)。
- Common Lisp:有很多好书可供学习。可以通过Common Lisp学习很多Lisp概念(包括面向对象编程)。强烈推荐。Common Lisp内置了最重要的Lisp设施,库提供了其余部分。周围有大量的东西可以学习。
- Scheme:70年代创建的不同Lisp方言。与Emacs Lisp或Common Lisp不直接兼容。有很多优秀的书籍和其他教程材料。强烈推荐学习Lisp基础知识和一些更高级的内容。你越深入地挖掘Scheme,它看起来就越不同于Emacs Lisp甚至Common Lisp。
- Clojure:非常不同的Lisp方言。与Common Lisp、Emacs Lisp或Scheme不兼容。共享一些概念,某些概念的工作方式不同。有好书。如果您想学习一些Lisp或特别是Clojure,强烈推荐。Clojure强调函数式和并发编程-非常相关的主题。
如果您想学习更多主流Lisp(具有典型Lisp方言的外观和感觉),我建议使用Common Lisp或Scheme。
对于学习Lisp的语言偏好(!),我的排序如下:
1. Common Lisp
2. Scheme
3. Clojure
4. Emacs Lisp
举个例子:
这是1960年写成的McCarthy's Lisp中的
COLLAPSE
函数(来自
Lisp I Programmer's manual, 1960,第101页)。它基本上是许多Lisp练习中的
FLATTEN
函数。它获取一个嵌套列表,并返回一个新列表,其中原子在单个列表中。
DEFINE
(((COLLAPSE,(LAMBDA,(L),(COND,
((ATOM,L),(CONS,L,NIL))
((NULL,(CDR,L)),
(COND,((ATOM,(CAR,L)),L),(T,(COLLAPSE,(CAR,L)))))
(T,(APPEND,(COLLAPSE,(CAR,L)),(COLLAPSE,(CDR,L)))))
))))))
这是
Common Lisp版本。你可以保持它为大写或转换为小写。两种方式都可行。
(DEFUN COLLAPSE (L)
(COND
((ATOM L) (CONS L NIL))
((NULL (CDR L))
(COND ((ATOM (CAR L)) L)
(T (COLLAPSE (CAR L)))))
(T (APPEND (COLLAPSE (CAR L))
(COLLAPSE (CDR L))))))
基本上是一样的。只有定义函数的形式有不同的名称和语法。否则代码完全相同。
试试在Common Lisp中使用麦卡锡的示例:
CL-USER > (COLLAPSE '(((A B) ((C))) ((D (E F)) (G) ((H)))))
(A B C D E F G H)
它运行了。
现在让我们尝试在使用GNU Emacs的Emacs Lisp中运行它。Emacs Lisp使用小写标识符:
ELISP> (defun collapse (l)
(cond
((atom l) (cons l nil))
((null (cdr l))
(cond ((atom (car l)) l)
(t (collapse (car l)))))
(t (append (collapse (car l))
(collapse (cdr l))))))
ELISP> (collapse '(((a b) ((c))) ((d (e f)) (g) ((h)))))
(a b c d e f g h)
这段代码可以在不做任何改变的情况下在Emacs Lisp中运行。
你也可以在Scheme中获得类似的版本(只需进行轻微的重命名):
在Petite Chez Scheme中:
> (define collapse
(lambda (l)
(cond
((atom? l) (cons l '()))
((null? (cdr l))
(cond ((atom? (car l)) l)
(else (collapse (car l)))))
(else (append (collapse (car l))
(collapse (cdr l)))))))
我们可以使用
DEFINE
来定义一个函数。而
COND
稍微有些不同,
()
表示空列表。谓词(判断条件)后面加上了
?
符号。
> (collapse '(((a b) ((c))) ((d (e f)) (g) ((h)))))
(a b c d e f g h)
运行。
在Clojure中,它看起来会有所不同。 基本上,您必须重新思考大部分代码。
这是Clojure自己实现的flatten
:
(defn flatten
[x]
(filter (complement sequential?)
(rest (tree-seq sequential? seq x))))
你可以按照Lisp版本的精神编写
flatten
函数 - 它看起来仍然会有所不同。
来自
rosetta.org:
(defn flatten [coll]
(lazy-seq
(when-let [s (seq coll)]
(if (coll? (first s))
(concat (flatten (first s)) (flatten (rest s)))
(cons (first s) (flatten (rest s)))))))
名称不同,语法不同,语义不同(适用于惰性序列而非列表)。
像Common Lisp、Emacs Lisp、Visual Lisp、ISLISP等方言试图保留其遗产。
Scheme或Clojure等方言并不感到受名称和语法的约束。它们在各个方向上进行了创新。Scheme仍然提供了旧功能的直接版本。Clojure没有。Clojure程序员不会认为这是一个劣势。