我是clojure的新手,并试图比较一个字符列表,我遇到了一些令人困惑的行为。当直接比较连接的字符串版本时,为什么难以(不可能?)比较字符列表的相等性?
(identical? (\A \T \C \G) (\A \T \C \G) )
; ClassCastException java.lang.Character cannot be cast to clojure.lang.IFn user/eval672
;(NO_SOURCE_FILE:1)
(identical? '(\A \T \C \G) '(\A \T \C \G) )
;false
;convert to string
(identical? "ATCG" "ATCG" )
;True
答案 0 :(得分:10)
来自REPL:
user=> (doc identical?)
-------------------------
clojure.core/identical?
([x y])
Tests if 2 arguments are the same object
如果您了解Java编程语言,那么 相同? 的行为类似于Java中的 == 运算符处理参考文献。
你可以试试这个:
(= '(\A \T \C \G) '(\A \T \C \G) )
=> true
再次,在REPL:
user=> (doc =)
-------------------------
clojure.core/=
([x] [x y] [x y & more])
Equality. Returns true if x equals y, false if not. Same as
Java x.equals(y) except it also works for nil, and compares
numbers and collections in a type-independent manner. Clojure's immutable data
structures define equals() (and thus =) as a value, not an identity,
comparison.
所以不,比较Clojure中列表的相等性并不是不可能的,也绝对不难。 REPL是你最好的朋友。
答案 1 :(得分:1)
作为@Chiron answer的附录:你在Clojure中有三种平等。
=
(以及数字==
)特定于Clojure,是您最常使用的。它执行与类型无关的值比较,这意味着在该定义下,相同类别(整数与小数)和类似数据结构(例如,列表,向量和集合或映射以及对的序列)的数量可以相等。它也适用于纯Java类型。
(= 5 5N) ;; true
(import 'java.util.ArrayList)
(= '(:a :b)
(let [l (ArrayList.)
_ (.add l :a)
_ (.add l :b)]
l)) ;; true
所有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
,因为在编译的代码中创建了两个不同的列表实例(对于vector,map和set literals也是如此);作为结果/反例,这将起作用:
(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