2013-07-24 28 views
8

Một liên minh phân biệt trong F # được biên dịch thành một lớp trừu tượng và các tùy chọn của nó trở thành các lớp bê tông lồng nhau.F # có nhận thức được các biểu mẫu được biên soạn của các công đoàn bị phân biệt đối xử không?

type DU = A | B 

DU là trừu tượng trong khi DU.A và DU.B là bê tông.

Với ServiceStack, việc tuần tự hóa các loại thành chuỗi JSON và ngược lại có thể được tùy chỉnh bằng các hàm. Đối với các loại DU, đây là cách tôi có thể làm điều đó trong C#.

using ServiceStack.Text; 

JsConfig<DU.A>.SerializeFn = v => "A"; // Func<DU.A, String> 
JsConfig<DU.B>.SerializeFn = v => "B"; // Func<DU.B, String> 
JsConfig<DU>.DeserializeFn = s => 
    if s == "A" then DU.NewA() else DU.NewB(); // Func<String, DU> 

Có phải F # nhận thức về biểu mẫu được biên soạn của các công đoàn bị phân biệt? Làm thế nào tôi có thể nhận được loại DU.A trong F # tại thời gian biên dịch?

typeof<DU> // compiles 
typeof<DU.A> // error FS0039: The type 'A' is not defined 
typeof<A> // error FS0039: The type 'A' is not defined 

Tôi có thể dễ dàng đủ đăng ký chức năng cho quá trình deserialization trong F #.

open System 
open ServiceStack.Text 

JsConfig<DU>.RawDeserializeFn <- 
    Func<_, _>(fun s -> printfn "Hooked"; if s = "A" then A else B) 

Có thể đăng ký chức năng tuần tự hoàn toàn trong F # cho các loại cụ thể DU.A và DU.B không?

Trả lời

8

Trong khi tất cả các hành vi (các lớp trừu tượng, vv) không chỉ là một chi tiết implemenation, nó thực sự được định nghĩa bởi spec, những điều này không phải là accesible từ F # - đây là một trích dẫn từ spec

Một loại liên kết được biên dịch U có:

· Một thuộc tính getter tĩnh CLI UC cho mỗi trường hợp công đoàn rỗng C. Thuộc tính này nhận đối tượng đơn đại diện cho mỗi trường hợp .

· Một loại CLI lồng nhau UC cho mỗi trường hợp không null. Kiểu này có các thuộc tính thể hiện Item1, Item2 .... cho mỗi trường của trường hợp công đoàn hoặc một mục thuộc tính duy nhất nếu có chỉ một trường . Tuy nhiên, loại liên kết được biên dịch chỉ có một trường hợp không có loại lồng nhau. Thay vào đó, loại hình công đoàn đóng vai trò là loại trường hợp.

· Một phương pháp tĩnh CLI U.NewC cho mỗi trường hợp công đoàn không null C. Phương pháp này xây dựng một đối tượng cho trường hợp đó.

· Một thuộc tính cá thể CLI U.IsC cho từng trường hợp C. Thuộc tính trả về đúng hoặc sai cho trường hợp.

· Một thuộc tính cá thể CLI U.Tag cho từng trường hợp C. Thuộc tính tìm nạp hoặc tính toán thẻ số nguyên tương ứng với trường hợp.

· Nếu U có nhiều hơn một trường hợp, nó có một loại CLI lồng nhau U.Tags. Các U.Tags typecontains một số nguyên chữ cho mỗi trường hợp, trong tăng thứ tự bắt đầu từ số không.

· Loại kết hợp được biên dịch có các phương thức được yêu cầu để triển khai các giao diện được tạo tự động của nó, ngoài bất kỳ thuộc tính hoặc phương pháp do người dùng xác định nào .

Các phương pháp và thuộc tính này có thể không được sử dụng trực tiếp từ F #. Tuy nhiên, các loại này có List.Empty, Danh sách người dùng phải đối mặt.Nhược điểm, Option.None và Option.Some thuộc tính và/hoặc phương pháp.

Quan trọng, "các phương pháp và thuộc tính này có thể không được sử dụng từ F #".

+0

tôi tự hỏi nếu điều này là một phần của F # ngôn ngữ Spec, make này thực hiện F # trong JVM không thể? Bởi vì CLI là một phần của ngôn ngữ bây giờ. –

+0

@WeiMa - Tôi cho rằng thừa kế tương tự có thể được mô hình hóa trên JVM. Đã có một số thảo luận về việc trình biên dịch xuất ra JVM trên danh sách gửi thư, nhưng tôi không nghĩ có bất kỳ kế hoạch nghiêm túc nào. –

+0

@WeiMa: Lưu ý rằng ngôn ngữ F # hỗ trợ các tính năng như kiểu giá trị và các cuộc gọi đuôi mà JVM thậm chí không thể diễn tả. –

5

Thực tế là DU trong F # là một loại duy nhất là chìa khóa để tính hữu dụng của nó. Chiếc F # cách tiếp cận sẽ được sử dụng phù hợp với mô hình:

JsConfig<DU>.SerializeFn <- function 
    | A -> "A" 
    | B -> "B" 

này nên làm việc vì các trường hợp công đoàn không chỉ là loại lồng nhau trong C#, nhưng phân nhóm là tốt. Tất nhiên nếu ServiceStack không xem xét serializers loại cơ sở thì điều này sẽ không hoạt động.

4

Daniel là chính xác, bạn có thể thực hiện việc này bằng cách đăng ký chức năng tuần tự hóa cho loại cơ sở DU. Dưới đây là một ví dụ đầy đủ hơn

open System 
open ServiceStack.Text 

type DU = A | B 

let serialize = function 
    | A -> "A" 
    | B -> "B" 

let deserialize = function 
    | "A" -> A 
    | "B" -> B 
    | _ -> failwith "Can't deserialize" 

JsConfig<DU>.SerializeFn <- Func<_,_>(serialize) 
JsConfig<DU>.DeSerializeFn <- Func<_,_>(deserialize) 

let value = [| A; B |] 
let text = JsonSerializer.SerializeToString(value) 
let newValue = JsonSerializer.DeserializeFromString<DU[]>(text) 

Kết quả:

val value : DU [] = [|A; B|] 
val text : string = "["A","B"]" 
val newValue : DU [] = [|A; B|]