Clojure函数方案(替代)

时间:2020-04-06 09:38:06

标签: clojure lisp common-lisp

我正在阅读Paul Graham的The Roots of Lisp

我试图转换第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)))))

3 个答案:

答案 0 :(得分:4)

“小提琴琴,传统”

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

由于规范不清楚,因此很难在Clojure代码中暗示可能的修复: 如果您遵循这封信的 Lisp根源,您将在Clojure之上实现Lisp,subst可能与本书中的类似。 但是,如果您想实现Lisp中常用的subst,则此处显示的代码将无法实现。

即使Clojure具有consnil?函数,它们的含义也不与Common Lisp中的相同(分别为consnull):请参见{{3 }}以获取详细信息。 在翻译subst之前,您必须确定Clojure的惯用做法是什么。

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

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

可能的出发点是阅读clojure: no cons cells,以确定构成AST的对象集,并查看您要执行哪种代码遍历。

我的建议是首先独立学习那些语言。有了彼此的一点经验,您将有更好的方法来了解彼此之间的相似性和差异性。

答案 1 :(得分:2)

方案版本的翻译可能看起来像这样:

(defn my-subst [new old data]
  (when-not (nil? data)
    (cond (sequential? data) (cons (my-subst new old (first data))
                                   (my-subst new old (next data)))
          (= data old) new
          :else data)))

user> (my-subst 1 :x '(1 2 :x (:x 10 :x [:x :z :x])))
;;=> (1 2 1 (1 10 1 (1 :z 1)))

这非常接近(尽管不完全相同,因为存在多种本机集合类型,这使您面临选择:应将哪些视为替代目标)。此示例处理“ listy”(顺序)结构,同时省略了哈希映射和集合。 另一个问题是保留原始序列的类型AND形式,这听起来并不简单(例如(into (empty (list 1 2 3)) (list 1 2 3)) => (3 2 1)

因此,您要做的是首先确定替换的语义,而在方案中,这只是自然的列表处理。

clojure.walk开始,使用它进行替换的最简单方法可能是

(defn subst [new old data]
  (clojure.walk/prewalk-replace {old new} data))

user> (subst :z :x [1 :x 3 '(:x {:a :x}) #{:x 1}])
;;=> [1 :z 3 (:z {:a :z}) #{1 :z}]

答案 2 :(得分:-2)

这就是我要做的,包括进行验证的单元测试:

(ns tst.demo.core
  (:use tupelo.core tupelo.test)
  (:require [clojure.walk :as walk]))

(defn subst
  [replacement target listy]
  (walk/postwalk (fn [elem]
                   (if (= elem target)
                     replacement
                     elem))
    listy))

(dotest
  (is= (subst :m :b [:a :b [:a :b :c] :d])
    [:a :m [:a :m :c] :d]))

但是,即使我认为Paul Graham的书Hackers & Painters确实令人不寒而栗,我也不会花很多时间阅读有关Common Lisp的40年历史的文章。

Clojure已将Lisp的最新技术发展了至少一个数量级(我想说的更像是2)。主要改进包括JVM的使用,持久性数据结构,并发性,语法和数据文字,仅举几例。

请查看Clojure learning resources的此列表,并可能从获取Clojure 或类似内容开始。


更新

有关Clojure的 Paul Graham 的更多信息

enter image description here