2013-03-28 31 views
5

Tôi nghĩ đó là giới hạn nổi tiếng của F # nhưng tôi không thể tìm thấy bất kỳ giải pháp nào tốt ...F # trích dẫn, mảng và tự nhận dạng trong các nhà xây dựng

Vì vậy, đây là mã (tôi đã cố gắng làm cho nó như là đơn giản càng tốt, vì vậy có thể có vẻ như nó không thực hiện bất kỳ cảm giác):

[<ReflectedDefinition>] 
type Human (makeAName: unit -> string) as self = 
    let mutable cats : Cat array = [| |] 
    do 
     // get a cat 
     cats <- Array.append cats [| new Cat (self, makeAName()) |] 
    member this.Cats = cats 
and 
[<ReflectedDefinition>] 
Cat (owner : Human, name : string) = class end 

Trình biên dịch nói:

lỗi FS0452: Báo giá không thể chứa mã lắp ráp nội tuyến hoặc mô hình kết hợp trên mảng

Thực ra nó là sự kết hợp của as self và trình thu thập thuộc tính mảng phá vỡ mọi thứ.

Những điểm ở đây là:

  • Tôi thực sự muốn sử dụng mảng, vì tôi muốn WebSharper để dịch các bộ sưu tập của tôi để mảng JavaScript.
  • Tôi thực sự cần một số nhận dạng tự trong các nhà xây dựng.
  • Tôi thực sự cần các lớp học (nghĩa là kiểu chức năng sẽ không hoạt động).
  • Tự nhận dạng theo từng phương thức (member this.Foo) hoạt động tốt.

Một cách giải quyết khác mà tôi có thể nghĩ là tạo các hàm tạo riêng và sử dụng các phương pháp tĩnh để xây dựng các đối tượng. Bằng cách này tôi không cần as self. Nhưng nó chỉ là ngớ ngẩn.

Có tùy chọn nào tốt hơn không?


Cập nhật:

Dưới đây là một ví dụ thậm chí đơn giản hơn:

[<ReflectedDefinition>] 
type User (uid: int) as self = 
    let ROOT_UID = 0 
    member this.isRoot = (uid = ROOT_UID) 

Với as self Tôi thậm chí không thể định nghĩa một lớp liên tục. Vâng, nó thực sự là một câu hỏi riêng biệt, nhưng tôi sẽ hỏi nó ở đây: làm thế nào để xác định một hằng số lớp trong trường hợp cụ thể này?


Trả lời

8

Tôi không nghĩ rằng điều đó là ngớ ngẩn chút nào. Chúng tôi thực sự thích phương pháp xây dựng tĩnh cho rõ ràng, ngay cả trong mã mà không sử dụng WebSharper. Trong toàn bộ codebase IntelliFactory, chúng tôi hiếm khi, nếu sử dụng self.

Bạn đang nhấn hai giới hạn gây phiền nhiễu của trình biên dịch và trích dẫn F #. Như bạn chỉ ra, phương pháp tĩnh có thể giải quyết vấn đề self:

[<ReflectedDefinition>] 
type Human private (cats: ref<Cat []>) = 
    member this.Cats = !cats 

    static member Create(makeAName: unit -> string) = 
     let cats = ref [| |] 
     let h = Human(cats) 
     let cat = Cat(h, makeAName()) 
     cats := [| cat |] 
     h 

and [<ReflectedDefinition>] Cat (owner: Human, name: string) = 
    class 
    end 

Có rất nhiều cách khác để thực hiện điều này, ví dụ bạn có thể thoát khỏi ref gián tiếp.

Thứ hai, bạn thường nhận được FS0452 trong mã ReflectedDefinition với các hoạt động mảng, ngay cả trong các phương thức tĩnh thuần túy. Điều này thường có thể được giải quyết bằng cách sử dụng chức năng thư viện thay vì truy cập mảng trực tiếp (Array.iter, Array.map).

Đối với ví dụ thứ hai, bạn thực sự muốn điều này:

[<ReflectedDefinition>] 
module Users = 

    [<Literal>]  
    let ROOT_UID = 0 

    type User(uid: int) = 
     member this.isRoot = (uid = ROOT_UID) 

Các [<Literal>] chú thích sẽ cho phép bạn mô hình trận đấu trên hằng số của bạn, có thể thuận tiện nếu có nhiều hơn một.

Đối với số điểm của bạn:

  1. Tôi thực sự muốn sử dụng mảng - đó nên được OK
  2. Tôi thực sự cần một sự tự nhận diện - đó là không bao giờ cần thiết, giống như nhà xây dựng không
  3. tôi thực sự cần các lớp học (nghĩa là phong cách chức năng sẽ không hoạt động) - chắc chắn không đúng
  4. Mỗi phương thức tự định danh (thành viên này.Foo) làm việc tốt - có, và hữu ích
+0

Các hàm tạo static — fine.Speaking về ví dụ thứ hai, tốt, đúng, hằng số mô-đun không hoạt động nhưng tôi thực sự là một hằng số lớp đó là lý do tại sao tôi muốn đưa vào trong lớp. Có các hằng số lớp bên trong các lớp (và không phải không gian tên mô-đun gây ô nhiễm) có vẻ như là một điều hợp lý để làm. – kirelagin

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