【问题标题】:Replacing a symbol in a symbolic expression替换符号表达式中的符号
【发布时间】:2015-01-28 02:44:20
【问题描述】:

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

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

有什么帮助吗?谢谢

【问题讨论】:

    标签: functional-programming scheme lisp


    【解决方案1】:

    最快的方法是使用一个标志来指示替换是否已经完成,类似于:

    (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?,因为它没有在标准Scheme中定义;通常的做法是依次测试null? 然后pair?,并在else 子句中处理atom case。

    【讨论】:

    • 不要在else 中使用cond,只需将这些条件折叠到外部cond 中。 :-)
    • 您真的可以完全删除 null? 测试;如果你想从树中删除 '() 会发生什么?此实现无法做到这一点,但删除 null? 测试将立即解决该问题。
    • @JoshuaTaylor 该过程应该只删除符号,'() 在 Scheme 中不是符号(与 Common Lisp 中的 NIL 相对)。但是你是对的,可以省略测试,从而简化程序。谢谢
    【解决方案2】:

    这有点笼统(你可以替换符号以外的东西,你可以自定义测试,你可以指定任何特定数量的实例来替换,而不仅仅是一个),并且可能有点复杂乍一看,这比您要寻找的要多,但这是一个通过在内部使用延续传递样式辅助函数来工作的解决方案。主函数 subst-n 接受一个 new 元素和一个 old 元素,一个 tree,一个 test 和一个 count。它将第一个 countnew(与 test 相比)替换为 old(或全部,如果 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)
    

    【讨论】:

      猜你喜欢
      • 2011-12-16
      • 2020-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多