是否期望 identity returns 与其参数有所不同?
Is it expected that identity returns something different from its argument?
这是一个调用 identity
更改返回值的示例,在我看来这表明文档字符串 "Returns its argument." 不完全正确:
(let [x Double/NaN] (identical? x x)) ;=> false
(let [x (identity Double/NaN)] (identical? x x)) ;=> true
这是预期的吗?还是 identity
函数的错误?
您似乎发现了涉及 identity
、identical?
和原始与对象相等性的边缘情况。请注意,在 Java、java.lang.Double/NaN is a primitive:
中
public static final double NaN
但相同比较Java个对象:
; clojure.core
(defn identical?
"Tests if 2 arguments are the same object"
{:inline (fn [x y] `(. clojure.lang.Util identical ~x ~y))
:inline-arities #{2}
:added "1.0"}
([x y] (clojure.lang.Util/identical x y)))
// clojure/lang/Util.java
static public boolean identical(Object k1, Object k2){
return k1 == k2;
}
试试这个技巧将 NaN 强制转换为 Double 对象而不是未装箱的基元:
tupelo.core=> (let [x (Double. Double/NaN)]
(spyxx x)
(identical? x x))
x => java.lang.Double->NaN
true
我怀疑原始 NaN 的自动装箱 may/may 不会出现在不同的用例中,这是造成您所看到的差异的原因。
为 Alan 关于拳击的回答增添一点色彩:
您可能需要查看 ==
函数,它是这样实现的:
public boolean equiv(Number x, Number y){
return x.doubleValue() == y.doubleValue();
}
这会执行两个实际 double
的原始比较。你的例子, ==
:
(let [x (identity Double/NaN)] (== x x))
=> false
(let [x (identity Double/POSITIVE_INFINITY)] (== x x))
=> true
这是怎么回事?为什么 NaN == NaN
是假的?好吧,使用 ==
的原始比较实际上对于 NaN
应该 return 为假。它在 IEEE 754 中以这种方式指定,而 Java 以这种方式表现。它是唯一的 "number",与自身相比,它不等于自身。
顺便说一句,要了解对象相等性在 Java 中是多么奇怪,请参阅:
(identical? 127 127)
=> true
(identical? 128 128)
=> false
这是因为 java 缓存了前 2^8 个无符号整数,所以被比较的 127
在第一个例子中是同一个对象,但是 128
在第二个例子是不同的对象。因此,在检查相等性时需要注意一些问题!
但这里的主要内容是:identity
正在正常工作!比较事物时要小心,因为 "equality" 的概念不是那么简单!
identity
"return its argument"吗?
这取决于您所说的 参数 的意思。
- 如果是函数调用形式中的求值表达式,则不总是。
- 如果它是函数体在进入时在堆栈上看到的,那么是的,它是。
异常的产生是因为Clojure调用函数的方式。
- Clojure 函数是符合
IFn
的对象
界面.
- Clojure 函数调用转换为众多
invoke
函数对象的方法 - 为 arity 重载。
- 所有
invoke
方法都有 Object
个参数。
所有这一切的结果是,每个 Clojure 函数调用都将其每个参数转换为某种类型的 Object
- 除了原语之外的身份操作,它们被包装在相应的 Java class:long
变成Long
,依此类推。
因此,即使是 identity
函数,本质上 (defn identity [x] x)
,也不是 return 原始参数。它不能,因为它从来没有看到它。
例如,让我们考虑表达式
(inc 3)
数3
肯定是long
。 (inc 3)
是什么类型?让我们问问 Clojure:
(type (inc 3))
=> java.lang.Long
... 盒装 Long
对象。
等一下,我们确定 3
是原始 long
吗?:
(type 3)
=> java.lang.Long
啊啊啊啊啊!也是盒装的!
不一定!你不知道,因为当 type
的主体看到 3
时,它 是 装箱的,无论 [=120 是否如此=]. Clojure documentation 在这一点上保持沉默。它只是说数字文字 通常表示为 Java。
所以 - 一般来说 - 它是评估机制,而不是负责装箱原始参数的特定函数(例如 identity
)。这是自动装箱。
你的例子表明基元是这样保存的,未装箱,至少在 let
形式中:
(let [x 1.0] (identical? x x)) ;=> false
(let [x (identity 1.0)] (identical? x x)) ;=> true
事实上identical?
能够区分1.0
的两个拳法,这表明它是作为原始double
持有的。 (我使用了一个普通的 double
,只是为了表明该行为与特殊值 Double/NaN
无关)。
现在让我们尝试将数字放入变量中:
(def x 1.0)
(identical? x x) ;=> true
(let [x (identity x)] (identical? x x)) ;=> true
它是盒装的。
虽然我们在这里,但自动装箱是幂等的:
(identical? x (identity x)) ;=> true
以上内容对 and 的回答以及 Alan Malloy 和 Lee 的评论所包含的内容没有什么补充。我只是觉得他们只是钩住了鱼,并没有真正把鱼钓上来。
这是一个调用 identity
更改返回值的示例,在我看来这表明文档字符串 "Returns its argument." 不完全正确:
(let [x Double/NaN] (identical? x x)) ;=> false
(let [x (identity Double/NaN)] (identical? x x)) ;=> true
这是预期的吗?还是 identity
函数的错误?
您似乎发现了涉及 identity
、identical?
和原始与对象相等性的边缘情况。请注意,在 Java、java.lang.Double/NaN is a primitive:
public static final double NaN
但相同比较Java个对象:
; clojure.core
(defn identical?
"Tests if 2 arguments are the same object"
{:inline (fn [x y] `(. clojure.lang.Util identical ~x ~y))
:inline-arities #{2}
:added "1.0"}
([x y] (clojure.lang.Util/identical x y)))
// clojure/lang/Util.java
static public boolean identical(Object k1, Object k2){
return k1 == k2;
}
试试这个技巧将 NaN 强制转换为 Double 对象而不是未装箱的基元:
tupelo.core=> (let [x (Double. Double/NaN)]
(spyxx x)
(identical? x x))
x => java.lang.Double->NaN
true
我怀疑原始 NaN 的自动装箱 may/may 不会出现在不同的用例中,这是造成您所看到的差异的原因。
为 Alan 关于拳击的回答增添一点色彩:
您可能需要查看 ==
函数,它是这样实现的:
public boolean equiv(Number x, Number y){
return x.doubleValue() == y.doubleValue();
}
这会执行两个实际 double
的原始比较。你的例子, ==
:
(let [x (identity Double/NaN)] (== x x))
=> false
(let [x (identity Double/POSITIVE_INFINITY)] (== x x))
=> true
这是怎么回事?为什么 NaN == NaN
是假的?好吧,使用 ==
的原始比较实际上对于 NaN
应该 return 为假。它在 IEEE 754 中以这种方式指定,而 Java 以这种方式表现。它是唯一的 "number",与自身相比,它不等于自身。
顺便说一句,要了解对象相等性在 Java 中是多么奇怪,请参阅:
(identical? 127 127)
=> true
(identical? 128 128)
=> false
这是因为 java 缓存了前 2^8 个无符号整数,所以被比较的 127
在第一个例子中是同一个对象,但是 128
在第二个例子是不同的对象。因此,在检查相等性时需要注意一些问题!
但这里的主要内容是:identity
正在正常工作!比较事物时要小心,因为 "equality" 的概念不是那么简单!
identity
"return its argument"吗?
这取决于您所说的 参数 的意思。
- 如果是函数调用形式中的求值表达式,则不总是。
- 如果它是函数体在进入时在堆栈上看到的,那么是的,它是。
异常的产生是因为Clojure调用函数的方式。
- Clojure 函数是符合
IFn
的对象 界面. - Clojure 函数调用转换为众多
invoke
函数对象的方法 - 为 arity 重载。 - 所有
invoke
方法都有Object
个参数。
所有这一切的结果是,每个 Clojure 函数调用都将其每个参数转换为某种类型的 Object
- 除了原语之外的身份操作,它们被包装在相应的 Java class:long
变成Long
,依此类推。
因此,即使是 identity
函数,本质上 (defn identity [x] x)
,也不是 return 原始参数。它不能,因为它从来没有看到它。
例如,让我们考虑表达式
(inc 3)
数3
肯定是long
。 (inc 3)
是什么类型?让我们问问 Clojure:
(type (inc 3))
=> java.lang.Long
... 盒装 Long
对象。
等一下,我们确定 3
是原始 long
吗?:
(type 3)
=> java.lang.Long
啊啊啊啊啊!也是盒装的!
不一定!你不知道,因为当 type
的主体看到 3
时,它 是 装箱的,无论 [=120 是否如此=]. Clojure documentation 在这一点上保持沉默。它只是说数字文字 通常表示为 Java。
所以 - 一般来说 - 它是评估机制,而不是负责装箱原始参数的特定函数(例如 identity
)。这是自动装箱。
你的例子表明基元是这样保存的,未装箱,至少在 let
形式中:
(let [x 1.0] (identical? x x)) ;=> false
(let [x (identity 1.0)] (identical? x x)) ;=> true
事实上identical?
能够区分1.0
的两个拳法,这表明它是作为原始double
持有的。 (我使用了一个普通的 double
,只是为了表明该行为与特殊值 Double/NaN
无关)。
现在让我们尝试将数字放入变量中:
(def x 1.0)
(identical? x x) ;=> true
(let [x (identity x)] (identical? x x)) ;=> true
它是盒装的。
虽然我们在这里,但自动装箱是幂等的:
(identical? x (identity x)) ;=> true
以上内容对