2017-01-19 17 views
6

Tôi có một lớp chung trong F # với một tham số kiểu duy nhất, và muốn tạo một lớp tĩnh chứa các phương thức nhà máy. Khi tôi viết các lớp của tôi, trình biên dịch F # tạo ra một lỗi liên quan đến một "biến kiểu thoát khỏi phạm vi của nó". Câu hỏi của tôi là tại sao có lỗi và cách khắc phục.Loại phạm vi thoát biến khi kết hợp lớp chung và không chung chung

tôi đã tạo ra một đoạn tối thiểu kích thước chứng minh vấn đề:

type Foo<'a>(element : 'a) = 

    member this.Copy() = Bar.Create(element) 

and Bar = 

    static member Create(element : 'a) = new Foo<'a>(element) 

Các đệ quy lẫn nhau trong các loại là có vì tôi muốn loại Foo<'a> để có thể gọi các phương pháp nhà máy trong lớp tĩnh. Đoạn mã trên không biên dịch và lỗi là: "Kiểu suy luận gây ra biến loại a để thoát khỏi phạm vi của nó. Hãy xem xét thêm khai báo tham số kiểu rõ ràng hoặc điều chỉnh mã của bạn thành ít chung chung hơn". Lỗi được đăng ký là nằm trong phương thức Create của lớp Bar. Thật không may, tôi thực sự không hiểu vấn đề cũng như cách khắc phục. Bất kỳ ý tưởng?

Dưới đây là một quan sát bổ sung. Đoạn mã

type Foo<'a>(element : 'a) = 

    member this.Element = element 

and Bar = 

    static member Create(element : 'a) = new Foo<'a>(element) 

không biên dịch. Vì vậy, vấn đề dường như liên quan đến suy luận kiểu được thực hiện trên cơ sở phương pháp Copy() của lớp Foo<'a>. Hơn nữa, đoạn

type Foo<'a>(element : 'a) = 

    member this.Copy() = Bar.Create(element) 

and Bar = 

    static member Create<'a>(element) = new Foo<'a>(element) 

là một phiên bản hơn C# -like của mã (trong đó phương pháp tĩnh một cách rõ ràng được thực hiện chung chung), mà cũng không biên dịch, với các lỗi "Mã này được không đủ generic. Các loại biến 'a không thể được tổng quát bởi vì nó sẽ thoát khỏi phạm vi của nó. "

Trả lời

6

Loại suy luận cho các thành viên đệ quy thường yêu cầu chú thích loại trên ít nhất một số định nghĩa. Tuy nhiên, đôi khi bạn có thể tránh điều này bằng cách định nghĩa lại trật tự, như bạn có thể trong ít nhất repro đơn giản hóa của bạn:

type Bar = 
    static member Create(element) = Foo(element) 
and Foo<'a>(element:'a) = 
    member this.Copy() = Bar.Create(element) 

(lưu ý rằng tôi đã thậm chí loại bỏ các chú thích trên element trong Bar.Create).

Tôi không biết rằng có một giải thích dễ hiểu về chính xác những chú thích nào sẽ cần trong bất kỳ trường hợp cụ thể nào, thật không may.

2

Tôi thực sự nhìn thấy một lỗi khác nhau, về kiểu biến 'a là chưa được giải quyết, và tôi có thể khắc phục nó bằng cách parameterizing Bar với 'a:

type Foo<'a>(element : 'a) = 
    member this.Copy() = Bar.Create(element) 

and Bar<'a> = 
    static member Create(element : 'a) = new Foo<'a>(element) 

Tôi sợ rằng tôi không có một rất giải thích tốt lý do tại sao điều này là bắt buộc trong kịch bản mà bạn có các loại đệ quy lẫn nhau, chứ không phải khi bạn có loại Bar riêng biệt.

Tôi có xu hướng tránh các loại đệ quy lẫn nhau - các tình huống mà bạn không thể làm nếu không có chúng là rất hiếm. Hầu hết thời gian bạn có thể tái cơ cấu mã để tránh đệ quy, và thường kết thúc với một cái gì đó dễ đọc và tái cấu trúc hơn nếu cần thiết.

+2

Đồng ý về nhận xét về việc lưu giữ các loại đệ quy cùng lúc ở vịnh. –

4

Điều này dường như làm việc mà không làm Bar generic:

type Foo<'a>(element : 'a) = 
    member this.Copy() = Bar.Create element 
and Bar = 
    static member Create<'a>(element : 'a) : Foo<'a> = Foo(element) 

Online Demo

Không biết tại sao, chỉ cần tìm thấy qua thử và sai.

+1

Đó là một điều kỳ quặc. Có lẽ có một số tương tác giữa các biến kiểu trên kiểu 'Foo' và' Tạo' ở đây, vì kết quả của 'Tạo' được suy ra là' Foo <'a> 'mà không có chú giải nữa. Không thể tin rằng nó dự kiến ​​sẽ hoạt động theo cách đó. – scrwtp

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