4 ;; This file checks whether the `=` function correctly implements equality of
5 ;; hash-maps and sequences (lists and vectors). If not, it redefines the `=`
6 ;; function with a pure mal (recursive) implementation that only relies on the
7 ;; native original `=` function for comparing scalars (integers, booleans,
11 ;; Save the original (native) `=` as scalar-equal?
12 (def! scalar-equal? =)
14 ;; A simple `and` macro for two argument which doesn't use `=` internally
17 `(let* (and2_FIXME ~a)
18 (if and2_FIXME ~b and2_FIXME))))
20 ;; Implement `=` for two sequential arguments
21 (def! sequential-equal?
23 (if (scalar-equal? (count a) (count b))
26 (if (mal-equal? (first a) (first b))
27 (sequential-equal? (rest a) (rest b))
32 (def! hash-map-vals-equal?
34 (if (scalar-equal? 0 (count map-keys))
36 (let* [key (first map-keys)]
38 (and2 (contains? a key) (contains? b key))
39 (mal-equal? (get a key) (get b key)))
40 (hash-map-vals-equal? a b (rest map-keys))
43 ;; Implement `=` for two hash-maps
46 (let* [keys-a (keys a)]
47 (if (scalar-equal? (count keys-a) (count (keys b)))
48 (hash-map-vals-equal? a b keys-a)
51 ;; This implements = in pure mal (using only scalar-equal? as native impl)
55 (and2 (sequential? a) (sequential? b)) (sequential-equal? a b)
56 (and2 (map? a) (map? b)) (hash-map-equal? a b)
57 true (scalar-equal? a b))))
59 (def! hash-map-equality-correct?
62 (and2 (= {:a 1} {:a 1})
63 (not (= {:a 1} {:a 1 :b 2})))
66 (def! sequence-equality-correct?
69 (and2 (= [:a :b] (list :a :b))
70 (not (= [:a :b] [:a :b :c])))
73 ;; If the native `=` implementation doesn't support sequences or hash-maps
74 ;; correctly, replace it with the pure mal implementation
75 (if (not (and2 (hash-map-equality-correct?) (sequence-equality-correct?)))
78 (println "equality.mal: Replaced = with pure mal implementation")))