我正在阅读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)))))
答案 0 :(得分:4)
(这可以翻译为“翻译,叛徒”,但这样做会破坏双关语,而这本身很有趣)
由于规范不清楚,因此很难在Clojure代码中暗示可能的修复:
如果您遵循这封信的 Lisp根源,您将在Clojure之上实现Lisp,subst
可能与本书中的类似。
但是,如果您想实现Lisp中常用的subst
,则此处显示的代码将无法实现。
即使Clojure具有cons
和nil?
函数,它们的含义也不与Common Lisp中的相同(分别为cons
和null
):请参见{{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 的更多信息