Merge pull request #532 from dubek/vhdl-fix-defmacro
[jackhill/mal.git] / impls / lib / equality.mal
CommitLineData
513810af 1;; equality.mal
3e9b89d4 2
513810af
DM
3;; This file checks whether the `=` function correctly implements equality of
4;; hash-maps and sequences (lists and vectors). If not, it redefines the `=`
5;; function with a pure mal (recursive) implementation that only relies on the
6;; native original `=` function for comparing scalars (integers, booleans,
83665b4f 7;; symbols, strings, keywords, atoms, nil).
513810af
DM
8
9;; Save the original (native) `=` as scalar-equal?
10(def! scalar-equal? =)
11
3e9b89d4 12;; A faster `and` macro which doesn't use `=` internally.
b1a8dbd5 13(defmacro! bool-and ; boolean
bf6647fb
NB
14 (fn* [& xs] ; interpreted as logical values
15 (if (empty? xs)
16 true
b1a8dbd5
NB
17 `(if ~(first xs) (bool-and ~@(rest xs)) false))))
18(defmacro! bool-or ; boolean
bf6647fb
NB
19 (fn* [& xs] ; interpreted as logical values
20 (if (empty? xs)
21 false
b1a8dbd5 22 `(if ~(first xs) true (bool-or ~@(rest xs))))))
3e9b89d4 23
83665b4f 24(def! starts-with?
513810af 25 (fn* [a b]
b1a8dbd5
NB
26 (bool-or (empty? a)
27 (bool-and (mal-equal? (first a) (first b))
28 (starts-with? (rest a) (rest b))))))
513810af 29
513810af
DM
30(def! hash-map-vals-equal?
31 (fn* [a b map-keys]
b1a8dbd5
NB
32 (bool-or (empty? map-keys)
33 (let* [key (first map-keys)]
34 (bool-and (contains? b key)
35 (mal-equal? (get a key) (get b key))
36 (hash-map-vals-equal? a b (rest map-keys)))))))
513810af 37
513810af
DM
38;; This implements = in pure mal (using only scalar-equal? as native impl)
39(def! mal-equal?
40 (fn* [a b]
41 (cond
83665b4f
NB
42
43 (sequential? a)
b1a8dbd5
NB
44 (bool-and (sequential? b)
45 (scalar-equal? (count a) (count b))
46 (starts-with? a b))
83665b4f
NB
47
48 (map? a)
49 (let* [keys-a (keys a)]
b1a8dbd5
NB
50 (bool-and (map? b)
51 (scalar-equal? (count keys-a) (count (keys b)))
52 (hash-map-vals-equal? a b keys-a)))
83665b4f
NB
53
54 true
55 (scalar-equal? a b))))
513810af
DM
56
57(def! hash-map-equality-correct?
58 (fn* []
59 (try*
b1a8dbd5
NB
60 (bool-and (= {:a 1} {:a 1})
61 (not (= {:a 1} {:a 1 :b 2})))
513810af
DM
62 (catch* _ false))))
63
64(def! sequence-equality-correct?
65 (fn* []
66 (try*
b1a8dbd5
NB
67 (bool-and (= [:a :b] (list :a :b))
68 (not (= [:a :b] [:a :b :c])))
513810af
DM
69 (catch* _ false))))
70
71;; If the native `=` implementation doesn't support sequences or hash-maps
72;; correctly, replace it with the pure mal implementation
b1a8dbd5
NB
73(if (not (bool-and (hash-map-equality-correct?)
74 (sequence-equality-correct?)))
513810af
DM
75 (do
76 (def! = mal-equal?)
77 (println "equality.mal: Replaced = with pure mal implementation")))