替换符号表达式中的符号

时间:2014-11-29 18:38:58

标签: functional-programming scheme lisp

我希望在对中替换第一次出现的符号。例如: 采取

(define n '((a . b) . (a . d)))

我定义了一个方法上下文来替换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)

任何帮助?谢谢

2 个答案:

答案 0 :(得分:0)

最快捷的方法是使用一个标志,指示替换是否已经完成,具体如下:

(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-values代码在可读性方面会更糟糕IMO

另请注意,我没有使用atom?,因为它没有在标准方案中定义;通常的方法是先后测试null?然后pair?,并处理else子句中的原子大小写。

答案 1 :(得分:0)

这是更通用的(您可以替换除符号之外的其他内容,并且您可以自定义测试,并且您可以指定要替换的任何特定数量的实例,而不仅仅是一个),并且可能稍微复杂一些乍一看比你正在寻找的,但这里是一个解决方案,通过内部使用延续传递样式辅助函数。主要功能 subst-n 采用 new 元素,元素,测试计数。它将 new 的第一个 count 次出现(与 test 相比)替换为 old (或全部,如果< em> count 不是非负整数。)

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