mirror of
https://github.com/kanaka/mal.git
synced 2024-08-16 17:20:23 +03:00
add examples/eqaulity.mal
Implementations that don't have proper native comparison of hash-maps and sequences can load examples/equality.mal for a pure-mal implementation.
This commit is contained in:
parent
a076db29a0
commit
513810af6b
78
examples/equality.mal
Normal file
78
examples/equality.mal
Normal file
@ -0,0 +1,78 @@
|
||||
;;
|
||||
;; equality.mal
|
||||
;;
|
||||
;; This file checks whether the `=` function correctly implements equality of
|
||||
;; hash-maps and sequences (lists and vectors). If not, it redefines the `=`
|
||||
;; function with a pure mal (recursive) implementation that only relies on the
|
||||
;; native original `=` function for comparing scalars (integers, booleans,
|
||||
;; symbols, strings).
|
||||
;;
|
||||
|
||||
;; Save the original (native) `=` as scalar-equal?
|
||||
(def! scalar-equal? =)
|
||||
|
||||
;; A simple `and` macro for two argument which doesn't use `=` internally
|
||||
(defmacro! and2
|
||||
(fn* [a b]
|
||||
`(let* (and2_FIXME ~a)
|
||||
(if and2_FIXME ~b and2_FIXME))))
|
||||
|
||||
;; Implement `=` for two sequential arguments
|
||||
(def! sequential-equal?
|
||||
(fn* [a b]
|
||||
(if (scalar-equal? (count a) (count b))
|
||||
(if (empty? a)
|
||||
true
|
||||
(if (mal-equal? (first a) (first b))
|
||||
(sequential-equal? (rest a) (rest b))
|
||||
false))
|
||||
false)))
|
||||
|
||||
;; Helper function
|
||||
(def! hash-map-vals-equal?
|
||||
(fn* [a b map-keys]
|
||||
(if (scalar-equal? 0 (count map-keys))
|
||||
true
|
||||
(let* [key (first map-keys)]
|
||||
(if (and2
|
||||
(and2 (contains? a key) (contains? b key))
|
||||
(mal-equal? (get a key) (get b key)))
|
||||
(hash-map-vals-equal? a b (rest map-keys))
|
||||
false)))))
|
||||
|
||||
;; Implement `=` for two hash-maps
|
||||
(def! hash-map-equal?
|
||||
(fn* [a b]
|
||||
(let* [keys-a (keys a)]
|
||||
(if (scalar-equal? (count keys-a) (count (keys b)))
|
||||
(hash-map-vals-equal? a b keys-a)
|
||||
false))))
|
||||
|
||||
;; This implements = in pure mal (using only scalar-equal? as native impl)
|
||||
(def! mal-equal?
|
||||
(fn* [a b]
|
||||
(cond
|
||||
(and2 (sequential? a) (sequential? b)) (sequential-equal? a b)
|
||||
(and2 (map? a) (map? b)) (hash-map-equal? a b)
|
||||
true (scalar-equal? a b))))
|
||||
|
||||
(def! hash-map-equality-correct?
|
||||
(fn* []
|
||||
(try*
|
||||
(and2 (= {:a 1} {:a 1})
|
||||
(not (= {:a 1} {:a 1 :b 2})))
|
||||
(catch* _ false))))
|
||||
|
||||
(def! sequence-equality-correct?
|
||||
(fn* []
|
||||
(try*
|
||||
(and2 (= [:a :b] (list :a :b))
|
||||
(not (= [:a :b] [:a :b :c])))
|
||||
(catch* _ false))))
|
||||
|
||||
;; If the native `=` implementation doesn't support sequences or hash-maps
|
||||
;; correctly, replace it with the pure mal implementation
|
||||
(if (not (and2 (hash-map-equality-correct?) (sequence-equality-correct?)))
|
||||
(do
|
||||
(def! = mal-equal?)
|
||||
(println "equality.mal: Replaced = with pure mal implementation")))
|
Loading…
Reference in New Issue
Block a user