How to take intersection of pairs from two lists in scheme?

前端 未结 2 1692
走了就别回头了
走了就别回头了 2021-01-24 00:18

I am using this script from The little schemer, to get intersection of two sets. But I am getting unbound identifier error at \'member?\', can anyone please tell what\'s wrong w

相关标签:
2条回答
  • 2021-01-24 00:43

    My intersection solution:

    #lang racket
    (define (intersect set1 set2)
      (cond [(empty? set1) '()]
            [(empty? set2) '()]
    
            [(= (caar set1) (caar set2)) (cons (list (caar set1)
                                                     (+ (cadar set1)
                                                        (cadar set2)))
                                               (intersect (cdr set1) (cdr set2)))]
            [(< (caar set1) (caar set2)) (intersect (cdr set1) set2)]
            [else (intersect set1 (cdr set2))]))
    
    0 讨论(0)
  • 2021-01-24 00:50

    You have a typo in intersect where you have switched 1 with as lower case L. If you fix that your intersect seems fine by me if you are comparing symbols. Eg.

    (define intersect
      (lambda (set1 set2)
        (cond
          ((null? set1)(quote ()))
          ((member? (car set1) set2)
           (cons (car set1)
                 (intersect (cdr set1) set2)))
          (else (intersect (cdr set1) set2)))))
    
    (intersect '(a b c d) '(c d e f)) ; ==> (c d) 
    

    To make it compare other things than symbols, you need to change your member? so that it uses equal? instead of eq?. It will be like this:

    (define member?
      (lambda (a lat)
        (cond
          ((null? lat) #f)
          (else (or (equal? (car lat) a) ; changed eq? to equal? 
                    (member? a (cdr lat)))))))
    
    (intersect '((1 2)(3 4)(5 6)) '((9 10) (7 8) (5 6))) ; ==> ((5 6))
    

    Even after this. The symbol version above still works. In any LISP (Common Lisp and Scheme at least) you have member. It uses equal and evaluate to false (whatever is false in the implementation) when it's not found and if it's found it evaluates to the rest of the argument list starting from where the element was found (which is considered true):

    (member 'a '(x y a c)) ; ==> (a c)
    

    Using standard member instead of your own predicate:

    (define intersect
      (lambda (set1 set2)
        (cond
          ((null? set1)(quote ()))
          ((member (car set1) set2)
           (cons (car set1)
                 (intersect (cdr set1) set2)))
          (else (intersect (cdr set1) set2)))))
    
    (intersect '((1 2)(3 4)(5 6)) '((9 10) (7 8) (5 6))) ; ==> ((5 6))
    (intersect '(a b c d) '(c d e f)) ; ==> (c d) 
    

    EDIT 1

    It seems you are not searching for intersection but a special alist merge:

    #!r6rs
    (import (rnrs base)
            (rnrs lists))
    
    ;; if you dont have r6rs remove the above and
    ;; uncomment this rnrs/lists-6 memp
    #;(define (memp predicate? lst)
      (cond ((null? lst) #f)
            ((predicate? lst) lst)
            (else (memp predicate? (cdr lst)))))
    
    
    (define (alist-merge merge-proc alist-1 alist-2)
      (if (null? alist-1) 
          '()
          (let* ((name (caar alist-1))
                 (found (memp (lambda (x) (equal? (car x) name)) alist-2)))
            (if found
                (cons (merge-proc (car alist-1) (car found))
                      (alist-merge merge-proc
                                   (cdr alist-1)
                                   alist-2))
                (alist-merge merge-proc
                             (cdr alist-1)
                             alist-2)))))
    
    (define (alist-merge-add alist-1 alist-2)
      (alist-merge (lambda (x y)
                     (list (car x)
                           (+ (cadr x) (cadr y))))
                   alist-1
                   alist-2))
    
    (alist-merge-add '((1 2)(2 7)) '((1 3)(4 5))) ; ==> ((1 5))
    
    0 讨论(0)
提交回复
热议问题