我正在阅读Paul Graham的The Roots of List
我尝试过转换第5页上的函数subst
,其定义如下:
(defun subst (x y z)
(cond ((atom z)
(cond ((eq z y) x)
('t z)))
('t (cons (subst x y (car z))
(subst x y (cdr z))))))
对其对应的Clojure
实现。我没有使用任何一种语言的生产经验(我一直在阅读Clojure),因此,由于我正在阅读本文以了解LISP的起源,因此将不胜感激。我最接近的是这个(但这是非常错误的):
(defn subst
[x y z]
(if (not (nil? z)) z x)
(if (= z y) x z)
(cons (subst x y (first z))
(subst (x y (rest z)))))
(这可以翻译为“翻译,叛徒”,但这样做会破坏双关语,而这本身很有趣)
由于尚不清楚规范,因此很难在Clojure代码中暗示可能的修复。
即使Clojure作为cons
和nil?
函数,它们的含义也不与Common Lisp中的相同:有关详细信息,请参见clojure: no cons cells。在翻译subst
之前,您必须确定Clojure的惯用用法是什么。
通常subst
用于转换由cons单元组成的tree;请注意,例如subst
不会递归到向量,字符串等。在这些树中,树的特定子集是Lisp形式的树。实际上,subst
的一个重要用例是在代码生成过程中搜索并替换表单。
据我所知,如果将自己限制为Clojure Cons
类型,则将不支持将代码作为数据使用。由于Clojure代码也使用数组表示法,因此您可能需要递归到数组对象中。因此,如何翻译subst
并不是一个容易确定的问题。
一个可能的起点是阅读LispReader.java
,以确定构成AST的对象集,并查看您要执行哪种代码遍历。
我的建议是首先独立学习那些语言。有了彼此的一点经验,您将有更好的方法来了解彼此之间的相似性和差异性。
这就是我要做的,包括进行验证的单元测试:
LispReader.java
但是,尽管我真的认为Paul Graham的书(ns tst.demo.core
(:use tupelo.core tupelo.test)
(:require [clojure.walk :as walk]))
(defn subst
[pat tgt listy]
(walk/postwalk (fn [elem]
(if (= elem tgt)
pat
elem))
listy))
(dotest
(is= (subst :m :b [:a :b [:a :b :c] :d])
[:a :m [:a :m :c] :d]))
确实令人不寒而栗,但我不会花很多时间阅读有关Common Lisp的40年历史的文章。
Clojure已将Lisp的最新技术发展到至少一个数量级(我想说的更像是2)。主要改进包括JVM的使用,持久性数据结构,并发性,语法和数据文字,仅举几例。
请参阅此Hackers & Painters列表,并可能以Getting Clojure或类似名称开头。