Functional programming 替换符号表达式中的符号
我希望替换成对中第一个出现的符号。例如: 接受 我定义了一个方法上下文,将X的第一个实例(最左边)替换为“() 替换a应该给我:Functional programming 替换符号表达式中的符号,functional-programming,scheme,lisp,Functional Programming,Scheme,Lisp,我希望替换成对中第一个出现的符号。例如: 接受 我定义了一个方法上下文,将X的第一个实例(最左边)替换为“() 替换a应该给我: ((() . b) a . d) 但是,我被卡住了,因为我的方法替换了所有的实例,我不知道如何为此添加检查。 我的代码如下: (define (context s sym) (cond ((null? s) #f) ((atom? s) (if (equal? s sym) '() s )) (else (con
((() . b) a . d)
但是,我被卡住了,因为我的方法替换了所有的实例,我不知道如何为此添加检查。
我的代码如下:
(define (context s sym)
(cond ((null? s) #f)
((atom? s)
(if (equal? s sym) '() s ))
(else (cons (context (car s) sym)
(context (cdr s) sym)))))
它给出:(().b)(.d)
有什么帮助吗?谢谢最快的方法是使用一个标志,指示是否已完成更换,大致如下:
(define (context sxp sym)
(define done #f)
(let loop ((sxp sxp))
(cond (done sxp)
((pair? sxp) (cons (loop (car sxp)) (loop (cdr sxp))))
((eq? sym sxp) (set! done #t) '())
(else sxp))))
使用set不是很优雅
,但另一种方法是让过程返回2个值,结果是let value
代码在可读性方面会更差
还要注意,我没有使用atom?,因为它没有在标准方案中定义;通常的方法是依次测试
null?
,然后pair?
,并在else
子句中处理atom大小写。这有点通用(您可以替换符号以外的东西,也可以自定义测试,并且可以指定要替换的任何特定数量的实例,而不仅仅是一个),乍一看可能比您要寻找的要复杂一点,但这里有一个解决方案,它在内部使用延续传递样式的帮助函数。主函数subst-n包含新元素、旧元素、树、测试和计数。它用旧的(或全部,如果计数不是非负整数)替换新的(与测试相比)的第一次计数
不要在
else
中使用cond
,只需将这些条件折叠到外部的cond
:-)你真的可以删除空值吗?共测;如果要从树中删除“()”,会发生什么?这个实现不能做到这一点,但是要删除null吗?test将立即修复该问题。@JoshuaTaylor该过程只应删除符号,而”()
在Scheme中不是符号(与Common Lisp中的NIL相反)。但你是对的,测试可以省略,从而简化了程序。谢谢
(define (context sxp sym)
(define done #f)
(let loop ((sxp sxp))
(cond (done sxp)
((pair? sxp) (cons (loop (car sxp)) (loop (cdr sxp))))
((eq? sym sxp) (set! done #t) '())
(else sxp))))
(define (subst-n new old tree test count)
(let substs ((tree tree)
(count count)
(k (lambda (tree count) tree)))
(cond
;; If count is a number and zero, we've replaced enough
;; and can just "return" this tree unchanged.
((and (number? count) (zero? count))
(k tree count))
;; If the tree is the old element, then "return" the new
;; element, with a decremented count (if count is a number).
((test old tree)
(k new (if (number? count) (- count 1) count)))
;; If tree is a pair, then recurse on the left side,
;; with a continuation that will recurse on the right
;; side, and then put the sides together.
((pair? tree)
(substs (car tree) count
(lambda (left count)
(substs (cdr tree) count
(lambda (right count)
(k (cons left right) count))))))
;; Otherwise, there's nothing to do but return this
;; tree with the unchanged count.
(else
(k tree count)))))
> (display (subst-n '() 'a '((a . b) . (a . d)) eq? 1))
((() . b) a . d)
> (display (subst-n '() 'a '((a . b) . (a . d)) eq? 2))
((() . b) () . d)