Remove subsequence function (deep recursion) in scheme

大憨熊 提交于 2019-12-11 10:45:01

问题


Im trying to write a function called removesub* which accepts two arguments (l1 and l2). The function needs to return the second list with the first occurence of the subsequence removed. So, if the first list is '(a b c), the first a if the second list is removed, the first b that appears after the removed a is removed, and the first c that appears after the removed b is removed - no matter how deep the atoms are nested.

Working Example

Input: (removesub* '(a b) '(w (x b) ((a) ((y z))) b a))

Output: (w (x b) (() ((y z))) a)

My current attempt doesnt seem to work because I have no way of sharing the l1 argument between nested recursive calls i.e. ((pair? (car l2)) (cons (removesub* l1 (car l2)) (removesub* l1 (cdr l2)))) splits l1 into two separate instances resulting in the following result. How can I share the l1 value so every recursive calls knows if the others have found the first instance of a value in l1?

Working Example

Input: (removesub* '(a b) '(w (x b) ((a) ((y z))) b a))

Output: (w (x b) (() ((y z))) b)

Attempted Solution - Scheme

(define removesub*
  (lambda (l1 l2)
    (cond
      ((or (null? l1) (null? l2)) l2)
      ((pair? (car l2)) (cons (removesub* l1 (car l2)) (removesub* l1 (cdr l2))))
      ((eq? (car l1) (car l2)) (removesub* (cdr l1) (cdr l2)))
      (else (cons (car l2) (removesub* l1 (cdr l2)))))))

回答1:


You need to pass the resulting symbols to search for to the next iteration. THere are many ways to do this.

You can use a compound return in the helper

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

Notice I do car first then use both parts of the result to do the next.

Scheme/Racket can return more than one value with values

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

Not really a semantic difference over the first, but it might be a tad faster since in theory the results can stay on the stack rather than each result having to create a cons that can be GC-ed as fast as the stack unrolls.

You can use continuation passing style:

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

This works by the helper has a continuation argument. This is close to what many Scheme implementations actually do to your code before running.

You can use mutation

Probably the fastest and easiest, but then you need to use #!r6rs or another standard Scheme rather than #!racket as implementation language.



来源:https://stackoverflow.com/questions/35461929/remove-subsequence-function-deep-recursion-in-scheme

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!