2017-06-27 14 views
5

Dưới đây là ví dụ trong đó gọi số identity thay đổi giá trị trả về, có vẻ như tôi cho biết rằng chuỗi tài liệu "Trả về đối số của nó". không hoàn toàn đúng:Liệu người ta kỳ vọng rằng danh tính sẽ trả về một điều gì đó khác với lập luận của nó?

(let [x Double/NaN] (identical? x x)) ;=> false 
(let [x (identity Double/NaN)] (identical? x x)) ;=> true 

Đây có phải là dự kiến ​​không? Hoặc có phải là lỗi với hàm identity không?

+4

Điều này có thể do quyền anh - 'Double/NaN' trả về một số nguyên 'double' được đóng hai lần trong ví dụ đầu tiên nhưng chỉ một lần trong giây. – Lee

Trả lời

8

Dường như bạn đã tìm thấy trường hợp cạnh liên quan đến identity, identical? và nguyên thủy so với đối tượng bình đẳng. Lưu ý rằng trong Java, java.lang.Double/NaN is a primitive:

public static final double NaN 

Nhưng giống hệt so sánh Java Objects:

; 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; 
} 

Hãy thử mẹo này để buộc các NaN vào một đối tượng đúp thay vì một nguyên thủy không có hộp bọc:

tupelo.core=> (let [x (Double. Double/NaN)] 
    (spyxx x) 
    (identical? x x)) 

x => java.lang.Double->NaN 
true 

Tôi nghi ngờ rằng autoboxing của NaN nguyên thủy mà có thể/có thể không xảy ra với các trường hợp sử dụng khác nhau là nguyên nhân của sự khác biệt mà bạn đang thấy.

+0

Bí quyết cuối cùng cũng giống như những gì mà câu hỏi này được đặt ra: bạn mở hộp NaN lên thành Double, giống như nhận dạng trong câu hỏi. Nó không thực sự là một điều khác. Tôi nghĩ điều duy nhất mà câu trả lời này thiếu là một lời giải thích về lý do tại sao cả hai 'danh tính' và 'giống hệt nhau?' Đòi hỏi phải autoboxing. – amalloy

3

Để thêm một chút màu sắc vào câu trả lời của Alan trên boxing:

Bạn có thể muốn nhìn vào == chức năng, được thực hiện theo cách này:

public boolean equiv(Number x, Number y){ 
    return x.doubleValue() == y.doubleValue(); 
} 

này thực hiện một sự so sánh nguyên thủy của hai thực tế double s. Ví dụ của bạn, với ==:

(let [x (identity Double/NaN)] (== x x)) 
=> false 
(let [x (identity Double/POSITIVE_INFINITY)] (== x x)) 
=> true 

Điều gì đang xảy ra? Tại sao là NaN == NaN sai? Vâng, so sánh nguyên thủy sử dụng ==thực sự phải trả về false cho NaN. Nó được xác định kỳ lạ theo cách này trong IEEE 754 và Java hoạt động theo cách này. Đó là "số" duy nhất, khi so sánh với chính nó, không bằng chính nó.

Là một sang một bên, để xem cách bình đẳng đối tượng có thể là một điều kỳ lạ trong Java, thấy điều này:

(identical? 127 127) 
=> true 
(identical? 128 128) 
=> false 

Điều này là do java lưu trữ 2^8 ints unsigned đầu tiên, vì vậy 127 s được so sánh là cùng một đối tượng trong ví dụ đầu tiên, nhưng 128 s trong ví dụ thứ hai là các đối tượng khác nhau. Vì vậy, có một số gotchas để được nhận thức của với kiểm tra bình đẳng!

Nhưng takeaway chính ở đây là: identity đang hoạt động bình thường! Chỉ cần cẩn thận khi so sánh mọi thứ, vì khái niệm "bình đẳng" không đơn giản như vậy!

+0

Điều này không trả lời câu hỏi, đó là về thực tế là các giá trị trả về là khác nhau, và không phải về những gì cụ thể những giá trị trả lại được. –

0

identity"trả lại đối số"?

Điều đó tùy thuộc vào ý bạn của đối số .

  • Nếu đó là biểu thức đánh giá theo hình thức chức năng gọi, sau đó không phải lúc nào.
  • Nếu nó là nội dung của hàm nhìn thấy trên ngăn xếp khi nhập, sau đó có, nó.

Sự bất thường phát sinh do cách Clojure gọi hàm.

  • Chức năng clojure là các đối tượng tuân thủ the IFn interface.
  • Lệnh gọi hàm Clojure được dịch sang một trong nhiều phương thức invoke - quá tải cho tính chất - của đối tượng hàm.
  • Tất cả các phương pháp invoke có thông số Object.

Kết quả cuối cùng của tất cả điều này là tất cả các chức năng Clojure gọi dịch của nó mỗi đối số vào một số loại Object - một hoạt động bản sắc ngoại trừ trên nguyên thủy, được bọc trong lớp Java tương ứng: long vào Long, và vân vân .

Vì vậy, ngay cả chức năng identity, về cơ bản là (defn identity [x] x), không trả lại một đối số nguyên thủy. Nó không thể, bởi vì nó không bao giờ nhìn thấy nó.


Ví dụ, chúng ta hãy xem xét các biểu hiện

(inc 3) 

Số 3 chắc chắn là một long. Loại (inc 3) là gì? Hãy hỏi Clojure:

(type (inc 3)) 
=> java.lang.Long 

... một đóng hộpLong đối tượng.

Hằng ngày, chúng ta chắc chắn rằng 3 là một nguyên thủy long:

(type 3) 
=> java.lang.Long 

Aaaaaaagh! Nó được đóng hộp quá!

Không nhất thiết phải! Bạn không thể biết được, bởi vì khi cơ thể của type thấy 3, nó được đóng hộp, cho dù nó có được đọc cho người đọc/trình biên dịch hay không. Các Clojure documentation là im lặng vào thời điểm này. Nó chỉ nói rằng các chữ số là thường được biểu diễn theo Java.

Vì vậy - nói chung - đó là cơ chế đánh giá, không phải là một chức năng cụ thể (chẳng hạn như identity) chịu trách nhiệm về các đối số nguyên thủy đấm bốc. Đây là auto-boxing.

gì ví dụ của bạn hiển thị là nguyên thủy được tổ chức như vậy, un-đóng hộp, ít nhất là trong let hình thức:

(let [x 1.0] (identical? x x)) ;=> false 
(let [x (identity 1.0)] (identical? x x)) ;=> true 

Thực tế là identical? có khả năng phân biệt giữa hai Phòng riêng của 1.0 cho thấy rằng nó được tổ chức như một nguyên thủy double. (Tôi đã sử dụng thông thường double, chỉ để cho thấy rằng hành vi không liên quan gì đến giá trị đặc biệt Double/NaN).

Bây giờ chúng ta hãy thử đặt số lượng trong một var:

(def x 1.0) 

(identical? x x) ;=> true 
(let [x (identity x)] (identical? x x)) ;=> true 

Nó đóng hộp.

Trong khi chúng tôi đang ở đây, auto-boxing là idempotent:

(identical? x (identity x)) ;=> true 

Trên đây thêm chút với những gì Alan Thompson'sJosh's câu trả lời và Alan Malloy và ý kiến ​​của Lee bao gồm. Tôi chỉ cảm thấy họ đã nối và chơi cá, mà không thực sự hạ cánh nó.

Các vấn đề liên quan