2011-08-15 26 views
7

Các loại vật liệu làm phần mở rộnglỗi Loại phần mở rộng cho từ điển <'K, 'V>

module Dict = 

    open System.Collections.Generic 

    type Dictionary<'K, 'V> with 
    member this.Difference(that:Dictionary<'K, 'T>) = 
     let dict = Dictionary() 
     for KeyValue(k, v) in this do 
     if not (that.ContainsKey(k)) then 
      dict.Add(k, v) 
     dict 

cung cấp cho các lỗi:

The signature and implementation are not compatible because the declaration of the type parameter 'TKey' requires a constraint of the form 'TKey : equality

Nhưng khi tôi thêm các hạn chế nó mang lại cho các lỗi:

The declared type parameters for this type extension do not match the declared type parameters on the original type 'Dictionary<,>'

này đặc biệt bí ẩn vì phần mở rộng kiểu sau không có ràng buộc và wor ks.

Bây giờ tôi có những suy nghĩ kỳ lạ: là hạn chế chỉ khi các thành viên nhất định được truy cập?

Trả lời

4
module Dict = 

    open System.Collections.Generic 

    type Dictionary<'K, 'V> with 
    member this.Difference(that:Dictionary<'K, 'T>) = 
     let dict = Dictionary(this.Comparer) 
     for KeyValue(k, v) in this do 
      if not (that.ContainsKey(k)) then 
       dict.Add(k, v) 
     dict 

EDIT:.

Theo F# spec (14.11 Additional Constraints on CLI Methods)

Some specific CLI methods and types are treated specially by F#, because they are common in F# programming and cause extremely difficult-to-find bugs. For each use of the following constructs, the F# compiler imposes additional ad hoc constraints:

  • x.Equals(yobj) requires type ty : equality for the static type of x
  • x.GetHashCode() requires type ty : equality for the static type of x
  • new Dictionary<A,B>() requires A : equality , for any overload that does not take an IEqualityComparer<T>
+1

Tôi sẽ không bao giờ đến đó. Tại sao khởi tạo từ điển với bộ so sánh phá vỡ ràng buộc bình đẳng? – Daniel

+0

Cảm ơn, desco. Tôi cần phải ở lại để đọc một số thông tin về đêm khuya. – Daniel

+0

@ Daniel, tôi nghi ngờ rằng thông số kỹ thuật đọc vào ban đêm có thể sẽ có hiệu ứng ngược lại hơn là ở lại - dù sao thì tôi cũng vậy;) – Benjol

0

Sự cố là việc bạn sử dụng phương thức Add. Nếu bạn sử dụng phương thức này là Dictionary<TKey, TValue> thì F # sẽ thực thi rằng TKey có ràng buộc bình đẳng.

Sau khi phát xung quanh một chút, tôi không chắc chắn rằng thậm chí có thể viết phương thức mở rộng này. Hệ thống kiểu F # xuất hiện để buộc kiểu khai báo của phương thức mở rộng không có ràng buộc bổ sung nào so với kiểu gốc (tôi gặp lỗi bất cứ khi nào tôi thêm ràng buộc equality). Ngoài ra kiểu được liệt kê trong các phương thức mở rộng cá thể không thể khác với kiểu được liệt kê. Tôi đã thử một số cách và không thể làm điều này hoạt động chính xác.

Gần nhất tôi đã đi là phương pháp không mở rộng như sau

let Difference (this : Dictionary<'K, 'T>) (that:Dictionary<'K, 'T> when 'K : equality) = 
    let dict = Dictionary() 
    for KeyValue(k, v) in this do 
     if not (that.ContainsKey(k)) then 
      dict.Add(k, v) 
    dict 

lẽ khác F # ninja sẽ có thể chứng minh tôi sai

+0

Yikes ... những suy nghĩ kỳ lạ của tôi được xác nhận. Tôi đã thử nó một vài cách và nó cũng không có khả năng đối với tôi. – Daniel

2

như xa như tôi có thể nhìn thấy đoạn mã sau không lừa:

module Dict = 
open System.Collections.Generic 

type Dictionary<'K, 'V> with 
    member this.Difference(that: Dictionary<'K,'V2>) = 
     let diff = 
      this 
      |> Seq.filter (fun x -> not <| that.ContainsKey(x.Key)) 
      |> Seq.map (fun x -> x.Key, x.Value) 
     System.Linq.Enumerable.ToDictionary(diff, fst, snd) 
0

(EDIT:. CKoenig có một câu trả lời tốt đẹp)

Hm, tôi đã làm thậm chí không nhìn thấy một cách để làm điều này.

Đây là giải pháp không an toàn, có thể mang lại nguồn cảm hứng điên rồ cho người khác.

open System.Collections.Generic 

module Dict = 
    type Dictionary<'K, 'V> with  
    member this.Difference<'K2, 'T when 'K2 : equality>(that:Dictionary<'K2, 'T>) =  
     let dict = Dictionary<'K2,'V>()  
     for KeyValue(k, v) in this do   
      if not (that.ContainsKey(k |> box |> unbox)) then   
       dict.Add(k |> box |> unbox, v)  
     dict 

open Dict 

let d1 = Dictionary() 
d1.Add(1, "foo") 
d1.Add(2, "bar") 

let d2 = Dictionary() 
d2.Add(1, "cheese") 

let show (d:Dictionary<_,_>) = 
    for (KeyValue(k,v)) in d do 
     printfn "%A: %A" k v 

d1.Difference(d2) |> show 

let d3 = Dictionary() 
d3.Add(1, 42) 

d1.Difference(d3) |> show 

let d4 = Dictionary() 
d4.Add("uh-oh", 42) 

d1.Difference(d4) |> show // blows up at runtime 

Nhìn chung nó có vẻ như có thể có không có cách nào để thống nhất các loại KK2 mà không cũng buộc họ phải có sự bình đẳng cùng khó khăn mặc dù ...

(EDIT: có vẻ như gọi vào NET đó là bình đẳng-chế-agnostic là một cách tốt để tạo ra một từ điển trong sự vắng mặt của các hạn chế thêm)

+0

Ràng buộc đến từ đâu?Nó có liên quan đến việc sử dụng 'Add', như Jared chỉ ra không? Có cách nào khác để biết khi nào các ràng buộc như vậy được yêu cầu, ngoài trình biên dịch cho bạn biết? – Daniel

+0

Xem 14.11: http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/spec.html#_Toc270597662 – Brian

+0

dường như 'từ điển mới' thêm ràng buộc, giải thích tại sao' ToDictionary' là được. – Brian

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