2016-10-06 15 views
9

tôi muốn tạo một kiểu với một định nghĩa một chút như thế này:Mô phỏng một 'Any' gõ F #

type LeftRight<'left, 'right> = { 
    Left : 'left list 
    Right : 'right list 
    } 

và một vài chức năng:

let makeLeft xs = { Left = xs; Right = [] } 

let makeRight ys = { Left = []; Right = ys } 

và tôi muốn cung cấp một 'kết hợp' chức năng: (! rõ ràng)

let combine l r = { Left = l.Left @ r.Left; Right = l.Right @ r.Right } 

Khi tôi cố gắng và làm một cái gì đó, tôi nhận được các vấn đề như giá trị của tôi là chung chung:

let aaa = makeLeft [1;2;3] 
// Value restriction. The value 'aaa' has been inferred to have generic type 
// val aaa : LeftRight<int,'_a>  

Nếu tôi kết hợp một bên trái và một quyền, đá kiểu suy luận trong và tất cả mọi thứ của A-OK:

let bbb = makeRight [1.0;2.0;3.0] 
let comb = combine aaa bbb // LeftRight<int, float> 

nhưng tôi muốn sử dụng một chỉ lefts ngày của riêng mình. Tôi đã cố gắng tạo ra một 'Any' loại:

type Any = Any 

và rõ ràng quy định các loại trên makeLeft và makeRight:

let makeLeft xs : LeftRight<_, Any> = { Left = xs; Right = [] } 

let makeRight ys : LeftRight<Any, _> = { Left = []; Right = ys } 

mà làm cho các định nghĩa giá trị hạnh phúc, nhưng làm cho các kết hợp chức năng buồn:

Tôi cảm thấy như có thể là một cách xung quanh điều này với vô số voodoo với quá tải .Net của các cuộc gọi chức năng, nhưng tôi không thể làm cho nó hoạt động. Có ai đã thử điều này trước khi/có bất kỳ ý tưởng?

Trả lời

10

Hạn chế giá trị không phải là một vấn đề trong trường hợp này, bạn cần kết quả của makeLeft hoặc makeRight là chung nếu bạn hy vọng sử dụng chúng rộng rãi hơn nữa xuống dòng.

Trong F # (và OCaml), giá trị cú pháp chung phải được đánh dấu rõ ràng như vậy, với chú thích kiểu đầy đủ. Thật vậy, trình biên dịch báo cáo điều này:

lỗi FS0030: Giới hạn giá trị. Giá trị 'aaa' được suy ra là có loại chung val aaa: LeftRight Hoặc định nghĩa 'aaa' làm thuật ngữ dữ liệu đơn giản, làm cho nó trở thành hàm có đối số rõ ràng hoặc nếu bạn làm không có ý định chung, thêm chú thích kiểu.

Nếu không đi sâu vào chi tiết quá nhiều, điều này là để tránh các vấn đề có thể xảy ra khi kết hợp đa hình và tác dụng phụ. Nhược điểm là nó từ chối một số mã hoàn toàn an toàn như là một kết quả.

Vì vậy, giải pháp là đơn giản, chúng ta thực hiện những giá trị này một cách rõ ràng generic:

let aaa<'a> : LeftRight<int,'a> = makeLeft [1;2;3] 

let bbb<'a> : LeftRight<'a, float> = makeRight [1.0;2.0;3.0] 

Đưa chúng lại với nhau trong FSI:

let comb = combine aaa bbb;;; 
val comb : LeftRight<int,float> = {Left = [1; 2; 3]; 
           Right = [1.0; 2.0; 3.0];} 

Lưu ý rằng nếu bạn kết hợp mà không có sự ràng buộc trung gian, bạn không còn có một giá trị chung và loại thích hợp có thể được suy ra bởi mpiler:

combine (makeLeft [1;2;3]) (makeRight [1.0;2.0;3.0]);; 
val it : LeftRight<int,float> = {Left = [1; 2; 3]; 
           Right = [1.0; 2.0; 3.0];} 

* Để cụ thể hơn, hãy kiểm tra this article.

+0

Tuyệt vời, tôi không biết bạn có thể đặt các đối số chung về giá trị. Điều này sửa chữa nó mà không cần phải gây rối với các loại 'Bất kỳ' trên khắp nơi! –

+0

Điều đó nói rằng, có vẻ như điều này hơi lạ khi bạn có một ràng buộc kiểu - 'let aaa <'a khi' a: compare> = ...' không thể tổng quát được vì nó sẽ thoát khỏi phạm vi của nó. –

+0

@MattKemp Tôi không thấy có vấn đề gì với việc đó. Bạn đang đặt gì ở phía bên tay phải? – TheInnerLight