首页 > 解决方案 > Clojure 函数的方案(subst)

问题描述

我正在阅读 Paul Graham 的Lisp 的根源

我尝试转换subst第 5 页上的函数,其定义如下:

(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)))))

标签: clojurelispcommon-lisp

解决方案


“传统的,传统的”

(这可以翻译为“翻译者,叛徒”,但这样做会破坏双关语,这本身就很有趣)

很难在您的 Clojure 代码中暗示可能的修复,因为规范不清楚:如果您严格遵守Lisp 的根源,您将在 Clojure 之上实现一个 Lisp,并且subst可能类似于这本书。但是如果你想实现substLisp 中常用的,这里显示的代码是行不通的。

尽管 Clojure 具有consnil?功能,但它们的含义与 Common Lisp 中的不同(分别是consnull):有关详细信息,请参阅clojure: no cons cells。在你可以翻译之前subst,你必须确定在 Clojure 中做什么是惯用的。

通常subst用于转换由 cons 单元组成的;请注意,例如,subst它不会递归到向量、字符串等。在这些树中,树的特定子集是 Lisp 形式的树。事实上,一个重要的用例subst是在代码生成期间搜索和替换表单。

据我所知,如果您将自己限制为 ClojureCons类型,那么您将不支持将代码作为数据。由于 Clojure 代码还使用向量和映射,因此您可能需要递归到此类对象中。因此,如何翻译subst并不是一个容易指定的问题。

一个可能的起点是阅读LispReader.java以确定构成 AST 的对象集,并查看您想要执行哪种代码遍历。

我的建议是先独立学习这些语言。通过对每个方面的一些经验,您将有一个更好的方法来了解它们之间的相似之处和不同之处。


推荐阅读