5

Tôi có câu hỏi về nhà điều hành mặc định "=" (bằng) trong F #. Nó cho phép so sánh các loại công đoàn do người dùng định nghĩa. Câu hỏi đặt ra là: sự phức tạp của nó là gì? Ví dụ, chúng ta hãy xem xét loại sau:F # bằng độ phức tạp của toán tử

type Tree<'a> = 
    | Nil 
    | Leaf of 'a 
    | Node of Tree<'a> * Tree<'a> 

và cây sau:

let a : Tree<int> = Node (Node (Node (Leaf 1, Leaf 2), Node (Leaf 3, Node (Leaf 4, Leaf 5))), Node (Leaf 6, Nil)) 
let b : Tree<int> = Node (Node (Node (Leaf 1, Leaf 2), Node (Leaf 3, Node (Leaf 4, Leaf 5))), Node (Leaf 6, Nil)) 
let c : Tree<int> = Node (Node (Node (Leaf 1, Leaf 2), Nil), Node (Node (Leaf 3, Node (Leaf 4, Leaf 5)), Leaf 6)) 

Rõ ràng là mã này:

printfn "a = b: %b" (a = b) 
printfn "a = c: %b" (a = c) 
printfn "a = a: %b" (a = a) 

sản xuất sản lượng này:

a = b: true 
a = c: false 
a = a: true 

Tôi mong rằng "a = b "và" a = c "tổng hợp mất thời gian tuyến tính. Nhưng còn "a = a" thì sao? Nếu nó là hằng số gì về cấu trúc phức tạp hơn, như thế một:

let d : Tree<int> = Node (a, c) 
let e : Tree<int> = Node (a, c) 

nó sẽ đi qua toàn bộ de cấu trúc hoặc nó sẽ dừng lại ở "a = một" và "c = c "?

Trả lời

4

F # sử dụng bình đẳng cấu trúc trong khi triển khai mặc định Equals trong .NET sử dụng bình đẳng tham chiếu. Điều này có nghĩa là, trong trường hợp điển hình, so sánh bình đẳng là O (N) trong đó N là số trường trong đồ thị đối tượng được so sánh.

Nếu bạn muốn đảm bảo a = a được tối ưu hóa, bạn có thể ghi đè Equals để kiểm tra tính bình đẳng tham chiếu trước và quay lại bình đẳng về mặt cấu trúc nếu không. Bạn cần chú thích loại của mình với [<CustomEquality>].

Bạn có thể thấy việc thực hiện khá lâu dài về bình đẳng cấu trúc trong the F# source code on github. Để theo dõi phân cấp cuộc gọi, hãy bắt đầu với GenericEqualityObj on line 1412.

-1

EDIT: Câu trả lời gốc là sai.

Việc thực hiện thông thường của Equals() trong Net làm việc như thế này:

  • Hãy so sánh hai trường hợp bằng cách tham chiếu. Nếu cả hai đều tham chiếu đến cùng một đối tượng, hãy trả lại true.
  • So sánh các loại thời gian chạy của hai phiên bản. Nếu chúng khác nhau, hãy trả lại false.
  • So sánh từng trường trong loại theo cách bình đẳng. Nếu bất kỳ giá trị nào không bằng nhau, hãy trả lại false, nếu không trả lại true.

Vì một số lý do, F # bỏ qua bước đầu tiên, có nghĩa là độ phức tạp của thời gian luôn tuyến tính.

Kể từ khi trình biên dịch biết rằng ab đều giống nhau và một số subtrees của c là giống như một số subtrees của a, và nó cũng biết rằng họ là bất biến, nó về mặt lý thuyết có thể làm cho ab cùng một đối tượng và tái sử dụng một số các bộ phận của chúng trong c. Thời gian chạy thực hiện điều gì đó tương tự với các chuỗi, được gọi là string interning. Nhưng (dựa trên mã giải mã) có vẻ như trình biên dịch hiện không làm điều này.

+0

Người bỏ phiếu, quan tâm để nhận xét? – svick

+0

Tôi không phải là downvoter, nhưng "thực hiện thông thường của' Equals' "bạn mô tả không áp dụng cho F # unions. – Daniel

+0

Tại sao không? Nó cư xử chính xác như thế. – svick

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