检查clojure中的字符相等性

时间:2013-12-01 00:18:33

标签: clojure

我是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

2 个答案:

答案 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 Equality或Equivalence

=(以及数字==)特定于Clojure,是您最常使用的。它执行与类型无关的值比较,这意味着在该定义下,相同类别(整数与小数)和类似数据结构(例如,列表,向量和集合或映射以及对的序列)的数量可以相等。它也适用于纯Java类型。

(= 5 5N) ;; true

(import 'java.util.ArrayList)
(= '(:a :b)
   (let [l (ArrayList.)
         _ (.add l :a)
         _ (.add l :b)]
     l)) ;; true

Java Equality

所有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