首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >闭函数方案(subst)

闭函数方案(subst)
EN

Stack Overflow用户
提问于 2020-04-06 09:38:06
回答 3查看 320关注 0票数 0

我在看保罗·格雷厄姆的李斯特的根

我已经尝试过转换第5页中的函数subst,它的定义如下:

代码语言:javascript
复制
(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的根源。我最接近的是这个(但这是非常错误的):

代码语言:javascript
复制
(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)))))
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-04-06 17:14:13

我就是这样做的,包括一个单元测试来验证:

代码语言:javascript
复制
(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]))

然而,我不会花很多时间去阅读40年前在Common上发表的文章,尽管我认为保罗·格雷厄姆( Paul )的书“黑客与画家”让人心神不宁。

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

请查看这个Clojure学习资源列表,并可能从获取Clojure或类似的内容开始。

更新

以上是Paul Graham为您带来的更多信息。

票数 -2
EN

Stack Overflow用户

发布于 2020-04-06 14:30:44

"Traduttore,traditore“

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

很难在Clojure代码中提示可能的修复,因为规范还不清楚:如果您完全按照Lisp的根操作,那么您将在Clojure的基础上实现一个Lisp,subst可能与本书中的类似。但是,如果您想要实现在Lisp中常用的subst,这里所示的代码将无法实现。

尽管Clojure具有consnil?函数,但它们的含义与Common (resp )并不相同。consnull):详细信息请参见clojure:没有反单元格。在翻译subst之前,您必须确定在Clojure中应该做什么。

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

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

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

我的建议是先独立学习这些语言。有了一点经验,你将有一个更好的方式来了解他们之间有多么相似和有多不同。

票数 4
EN

Stack Overflow用户

发布于 2020-04-06 19:08:00

方案版本的翻译可能如下所示:

代码语言:javascript
复制
(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‘(顺序)结构,同时省略散列映射和集合。另一个问题是保留原始序列的类型和形式,这并不像听起来那么简单(例如(into (empty (list 1 2 3)) (list 1 2 3)) => (3 2 1) )。

所以你要做的是,首先决定替换的语义,而在方案中,它只是一个自然的列表处理。

对于已经提到的clojure.walk,使用它进行替换的最简单方法可能是

代码语言:javascript
复制
(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}]
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61056834

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档