Functional programming 替换符号表达式中的符号

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

我希望替换成对中第一个出现的符号。例如: 接受

我定义了一个方法上下文,将X的第一个实例(最左边)替换为“() 替换a应该给我:

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