[4/14/99] =============================================================================== * A feature of equal? is that it always check its arguments with eq? before it descends recursively. Here are some examples: -------------------- (define a '(1 2)) (define b (cons 0 a)) (define c (cons 0 a)) ;; these two are expected (eq? b c) --> #f (equal? b c) --> #t (define a '(1 2)) (make-chain a) ; this is what the PS solution is supposed to be (define b (cons 0 a)) (define c (cons 0 a)) ;; this is still obvious (eq? b c) --> #f ;; but the reason that this doesn't enter an infinite loop is that the ;; recursive call to equal? was checking eq? first (equal? b c) --> #t -------------------- However, if you're not careful enough with pointer and circular references you might find yourself in troubles - here is a quick example: -------------------- (define a '(1 2)) (make-chain a) (define b '(1 2)) (make-chain b) ;; obviously: (eq? a b) --> #f ;; but: (equal? a b) --> no value: it is stuck in an infinite loop! -------------------- The comparison of chains in the problem set is one way to compare such circular objects. =============================================================================== * Using equal? to compare functions: It is impossible to compare functions. It might seem reasonable to say that this form should evaluate to true: -------------------- (equal? (lambda (x) x) (lambda (x) x)) -------------------- but what about these examples: -------------------- ;; the 0 isn't used anyway (equal? (lambda (x) 0 x) (lambda (x) x)) ;; these two are doing _exactly_ the same thing (equal? (lambda (x) x) (lambda (y) y)) ;; these are also the same (equal? (lambda (x) (if 1 x x)) (lambda (x) (if 2 x x))) ;; these are the same only for numbers (equal? (lambda (x) (+ x 0)) (lambda (x) x)) -------------------- You might think that a possible solution is to define equality of functions as having the same syntax, but what about this: -------------------- (equal? (let ((y 1)) (lambda (x) y)) (let ((y 2)) (lambda (x) y))) -------------------- we get two lambda expressions with the exact same body but they are certainly different... Generally, the only way that we can compare two functoins for equality is running them on all possible inputs. The only case that equal? returns #t for two functions is when they are the same function pointer so they are in fact eq?. =============================================================================== * Equality of instances: Since objects in Swindle are implemented as lambda expressions (try (procedure? )), then equal? cannot go down inspecting their structure as we saw. For this, there is a generic function called equals? that by default is simply using equal? to compare objects. One thing that you've seen is that this is actually working on objects that are structure instances, this is because there is a default method for structures that compares all of the slots (actually the classes first, so you will get a #f for two instances of different structures with the same slots). However, this does not happen automatically for general classes. The reason is that equality is not always straightforward when you talk about general classes. So, to be able to compare the _structure_ of two instances, you have to define a method for equals? for these two objects. One reason that equals? does not necessarily mean "compare all slots recursively" is that you migt have circularities, and these might lead to infinite loops as shown above. =============================================================================== * Keywords: A keyword is a symbol that begins with ":". These are special symbols that are bound to themselves as their value. This is used by the object system but can also be used for general purpose as a convenient tool for using tag symbols. ===============================================================================