В качестве дополнения к @Chiron's answer: у вас есть три вида равенства в Clojure.
Clojure Равенство или Эквивалентность
=
(и ==
для чисел) является специфичным для Clojure и тот, который вы будете использовать больше всего. Он выполняет независимое от типа сравнение значений, что означает, что числа той же категории (целые числа против десятичных знаков) и аналогичные структуры данных (например, списки, векторы и множества или карты и последовательности пар) могут быть равны в соответствии с этим определением. Он также работает с чистыми Java-типами.
(= 5 5N) ;; true
(import 'java.util.ArrayList)
(= '(:a :b)
(let [l (ArrayList.)
_ (.add l :a)
_ (.add l :b)]
l)) ;; true
Java Равенство
Все типы Clojure являются Java-классы под капотом, поэтому все не нильполугруппы Clojure лица осуществлять .equals
, и для большинства типов Clojure он ведет себя так же, как =
бы. Но это меньше похожее на слепое сравнение; например, большинство типов Clojure - это чистые типы Java, а для всех числовых типов Java .equals
зависит от типа.
(.equals 5 5N) ;; false
Опасайтесь. There are many pitfalls in writing equality methods in Java. Многие разработчики библиотеки упали.
Идентичность объекта
identical?
ведет себя так же, как ==
оператор Java, который возвращает true
тогда и только тогда, когда оба параметра тот же экземпляр объекта; это равенство «адрес в памяти», поэтому более строгий инструмент доступен. Но иногда это именно то, что вам нужно.
Что касается поведения вы столкнулись:
(identical? '(\A \T \C \G) '(\A \T \C \G))
возвращает false
, потому что два различных экземпляра списка создаются в скомпилированный код (то же самое произошло бы с вектором, карта и набор литералов); как следствие/контр-пример, это будет работать:
(let [a '(A \T \C \G)]
(identical? a a))
Компилятор не видит два список литералов как идентичные; он видит только два параметра и компилирует каждый из них в качестве нового списка, следовательно, два отдельных экземпляра списка. Однако их содержимое во время выполнения одинаково, поскольку эти символьные литералы кэшируются; поэтому являются булевы литералы и некоторые (но не все) числовые литералы:
(identical? \A \A)
(identical? true true)
(identical? 5 5) ;; Long
(identical? 0N 0N) ;; BigInt
(identical? (byte 6)
(byte 6))
(identical? (short 7)
(short 7))
(identical? (int 8)
(int 8))
(identical? (biginteger 9)
(biginteger 9))
(identical? (bigdec 10)
(bigdec 10))
Большинство кэши типа имеют ограничения, хотя; все следующие не кэшируются (и, таким образом, возвращает identical?
false
):
;; Java cache limitations
(identical? (char 128) ;; Characters with codepoint outside of 0..127
(char 128)) ;; i.e. non-"C0 Control/Basic Latin" Characters
(identical? 128 128) ;; Longs/Integers/Shorts outside of -128..127
(identical? 0. 0.) ;; Doubles and Floats are not cached
(identical? (biginteger 17)
(biginteger 17)) ;; BigIntegers outside of -16..16
(identical? (bigdec 11)
(bigdec 11)) ;; BigDecimals outside of 0..10
;; Clojure cache limitations
(identical? 1N 1N) ;; 0N is the only cached BigInt literal
(identical? 0M 0M) ;; BigDecimal literals are not cached
(identical? 1/2 1/2) ;; Ratios are not cached
;; Note that Ratio literals of the form X/1
;; and any other reducible to an integer
;; e.g. 10/10 are compiled as integer types
;; (Long/BigInt)
(identical? "ATCG" "ATCG")
возвращает true
, потому что Clojure String
литералы интернирован; поэтому ключевые слова:
(identical? :foo :foo)
;; but not symbol literals
(identical? 'foo 'foo) ;; false
спасибо за быстрый ответ. (не могу поверить, что я не пробовал '=' first ....) – zach
Еще одно небольшое добавление от [this] (http://dev.clojure.org/display/design/Documentation+for+1.3+Numerics) : Оператор = равенство (равенство) проверяет равенство. Он сравнивает значения не зависящим от типа образом, но не между плавающими точками и целыми типами. Это позволяет использовать числа в качестве ключей карты с правильной семантикой. Чтобы проверить числовую эквивалентность между типами с плавающей точкой и целым числом, используйте оператор == (эквивалентность). –