Recursion 删除scheme中的子序列函数(深度递归)

Recursion 删除scheme中的子序列函数(深度递归),recursion,scheme,lisp,racket,Recursion,Scheme,Lisp,Racket,我正在尝试编写一个名为removesub*的函数,它接受两个参数(l1和l2)。函数需要返回第二个列表,并删除子序列的第一次出现。因此,如果第一个列表是”(a b c),那么第一个a如果第二个列表被移除,那么在移除的a之后出现的第一个b被移除,而在移除的b之后出现的第一个c被移除——不管原子嵌套的深度有多深 工作示例 输入:(删除sub*”(ab)“(w(x b)((a)((y z)))ba)) 输出:(w(xb)(()((yz)))a) 我当前的尝试似乎不起作用,因为我无法在嵌套递归调用之间共

我正在尝试编写一个名为
removesub*
的函数,它接受两个参数
(l1和l2)
。函数需要返回第二个列表,并删除子序列的第一次出现。因此,如果第一个列表是
”(a b c)
,那么第一个
a
如果第二个列表被移除,那么在移除的
a
之后出现的第一个
b
被移除,而在移除的
b
之后出现的第一个
c
被移除——不管原子嵌套的深度有多深

工作示例

输入:
(删除sub*”(ab)“(w(x b)((a)((y z)))ba))

输出:
(w(xb)(()((yz)))a)

我当前的尝试似乎不起作用,因为我无法在嵌套递归调用之间共享l1参数,即
((pair?(car l2))(cons(removesub*l1(car l2))(removesub*l1(cdr l2)))
将l1拆分为两个单独的实例,从而得到以下结果如何共享
l1
值,以便每个递归调用都知道其他调用是否在
l1
中找到了值的第一个实例?

工作示例

输入:
(删除sub*”(ab)“(w(x b)((a)((y z)))ba))

输出:
(w(xb)(()((yz)))b)

尝试解决方案-方案
您需要将要搜索的结果符号传递给下一个迭代。有很多方法可以做到这一点

您可以在助手中使用复合返回

(define (removesub* elements-in-order haystack)
  ;; just use a pair to pass result and the 
  ;; elements to continue searching for
  (define (result eio h)
    (cons eio h))

  (cdr
   (let rec ((eio elements-in-order)
             (h haystack))    
     (cond ((or (not (pair? eio))
                (not (pair? h)))
            (result eio h))
           ((pair? (car h))
            (let* ((r (rec eio (car h)))
                   (r2 (rec (car r) (cdr h))))
              (result (car r2) (cons (cdr r) (cdr r2)))))
           ((eq? (car eio) (car h))
            (rec (cdr eio) (cdr h)))
           (else
            (let ((r (rec eio (cdr h))))
              (result (car r) (cons (car h) (cdr r)))))))))
请注意,我首先执行
car
,然后使用结果的两部分执行下一步

方案/球拍可以返回多个带有值的值

(define (removesub* elements-in-order haystack)
  (define (helper eio h)    
    (cond ((or (not (pair? eio))
               (not (pair? h)))
           (values eio h))
          ((pair? (car h))
           (let*-values ([(eiocar hcar) (helper eio (car h))]
                         [(eiocdr hcdr) (helper eiocar (cdr h))])
             (values eiocdr (cons hcar hcdr))))
          ((eq? (car eio) (car h))
           (helper (cdr eio) (cdr h)))
          (else
           (let-values ([(eiocdr hcdr) (helper eio (cdr h))])
             (values eiocdr (cons (car h) hcdr))))))

  (let-values ([(eio result) (helper elements-in-order haystack)])
    result))
与第一个结果相比,这并不是一个真正的语义差异,但它可能要快一点,因为理论上,结果可以留在堆栈上,而不是每个结果都必须创建一个cons,该cons可以在堆栈展开时以同样快的速度进行GC

您可以使用连续传球方式:

(define (removesub* elements-in-order haystack)  
  (let cps ((eio elements-in-order)
            (h haystack)
            (c (lambda (eio h) h)))    
    (cond ((or (not (pair? eio))
               (not (pair? h)))
           (c eio h))
          ((pair? (car h))
           (cps eio
                (car h)
                (lambda (eio hcar)
                  (cps eio
                       (cdr h)
                       (lambda (eio hcdr)
                         (c eio (cons hcar hcdr)))))))
          ((eq? (car eio) (car h))
           (cps (cdr eio) (cdr h) c))
          (else
           (cps eio
                (cdr h)
                (lambda (eio res)
                  (c eio (cons (car h) res))))))))
这项工作由具有continuation参数的助手完成。这与许多Scheme实现在运行之前对代码所做的实际操作非常接近

您可以使用变异


可能是最快和最简单的,但是您需要使用
#!r6rs
或其他标准方案,而不是
#!racket
作为实现语言。

谢谢您的回答。CPS样式的参数名称的含义是什么?
eio
是否等同于
l1
haystack
是否等同于
l2
?@stack\u pooper是。我发现
l1
l2
是不好的名字,因为这样看来,参数只是类似的列表。事实上,第一个是搜索内容的列表,第二个是生成结果的源。此外,如果我为自己编写代码,我会在命名let中隐藏变量(使用相同的名称),但当我学习方案时,我发现隐藏令人困惑。为什么
(或(不是(对?eio))(不是(对?h)))
而不是
(或(不是(空?eio))(不是(空?h)))
在CPS样式中?@stack\u pooper如果第一个术语不匹配,您肯定知道
eio
h
都是成对的。如果您执行
(或(null?eio)(null?h))
则无法确定它是否是一对,因为您唯一要检查的是是否有空。请尝试
(removesub*'(ab c)10)
(removesub*'symbol'(ab c))
查看差异。谢谢。你介意看看这个问题吗?
(define (removesub* elements-in-order haystack)  
  (let cps ((eio elements-in-order)
            (h haystack)
            (c (lambda (eio h) h)))    
    (cond ((or (not (pair? eio))
               (not (pair? h)))
           (c eio h))
          ((pair? (car h))
           (cps eio
                (car h)
                (lambda (eio hcar)
                  (cps eio
                       (cdr h)
                       (lambda (eio hcdr)
                         (c eio (cons hcar hcdr)))))))
          ((eq? (car eio) (car h))
           (cps (cdr eio) (cdr h) c))
          (else
           (cps eio
                (cdr h)
                (lambda (eio res)
                  (c eio (cons (car h) res))))))))