2010-07-29 24 views
15

Nói rằng tôi có một danh sách các hình dạng:F #: làm thế nào để lựa chọn thanh lịch và nhóm các công đoàn phân biệt đối xử?

type shape = 
| Circle of float 
| Rectangle of float * float 

let a = [ Circle 5.0; Rectangle (4.0, 6.0)] 

Làm thế nào tôi có thể sau đó kiểm tra ví dụ một vòng tròn tồn tại trong một? Tôi có thể tạo chức năng cho mỗi hình dạng

let isCircle s = 
    match s with 
    | Circle -> true 
    | _ -> false 
List.exists isCircle a 

nhưng tôi cảm thấy phải có cách thanh lịch hơn trong F #, ngoài việc phải xác định chức năng như vậy cho từng loại hình dạng. Lanhung?

câu hỏi liên quan là làm thế nào để nhóm một danh sách các hình dạng, dựa trên các loại hình dạng:

a |> seq.groupBy(<shapetype? >) 
+2

(hơi OT) Điều này nhắc tôi, thời gian cao mà [làm nổi bật mã được hỗ trợ cho F #] (http://meta.stackexchange.com/questions/58934/hight-time-for-code-highlighting-f-snippets) (!) – Abel

+0

Xem http://meta.stackexchange.com/questions/981/syntax-highlighting-hints không có đánh dấu ngôn ngữ cụ thể trên SO. – Brian

Trả lời

7

bạn có thể kết hợp F # phản ánh với trích dẫn để có được giải pháp chung

type Shape = 
    | Circle of float 
    | Rectangle of float * float 

let isUnionCase (c : Expr<_ -> 'T>) = 
    match c with 
    | Lambdas (_, NewUnionCase(uci, _)) -> 
     let tagReader = Microsoft.FSharp.Reflection.FSharpValue.PreComputeUnionTagReader(uci.DeclaringType) 
     fun (v : 'T) -> (tagReader v) = uci.Tag 
    | _ -> failwith "Invalid expression" 

let a = 
    [ Circle 5.0; Rectangle (4.0, 6.0)] 
     |> List.filter (isUnionCase <@ Rectangle @>) 
printf "%A" a 
+0

Việc thực hiện isUnionCase là cách trên đầu của tôi, nhưng nó trông rất thông minh. Và sử dụng nó là dọc theo dòng tôi nghi ngờ nó có thể giống như thế. Cảm ơn! – Emile

+1

Tôi dường như không thể tìm được không gian tên chính xác. Microsoft.FSharp.Quotations là cần thiết cho Expr nhưng tôi không thể tìm thấy Lambdas bất cứ nơi nào – Wouter

+0

'Lambda' (lưu ý, không ** s **) và' NewUnionCase' có thể được tìm thấy dưới không gian tên 'Microsoft.FSharp.Quotations.Patterns'. – Ruxo

0

Một giải pháp thanh lịch hơn có thể là như sau:

let shapeExistsInList shapeType list = 
    List.exists (fun e -> e.GetType() = shapeType) list 

let circleExists = shapeExistsInList ((Circle 2.0).GetType()) a 

Tuy nhiên, tôi không phải là rất hài lòng với điều này bản thân mình kể từ khi bạn phải tạo ra một thể hiện của các công đoàn phân biệt đối xử cho nó để làm việc.

Nhóm theo loại hình có thể hoạt động theo cách tương tự.

+2

Điều này làm việc trong trường hợp này nhưng không phải cho các loại đơn giản như 'loại T = A | B' trong đó các trường hợp * không * được triển khai dưới dạng các loại khác nhau. – Mau

+0

Như một sang một bên: Đó là cùng một vấn đề - của việc phải tạo một cá thể lớp để kiểm tra một cá thể lớp - luôn luôn xuất hiện. Nó sẽ là thú vị để xem một số giải pháp chung cho vấn đề. Nó có thể có giá trị bắt đầu một chủ đề hoặc một wiki. – TechNeilogy

+0

Không biết rằng .. –

16

Nếu bạn quan tâm trong các danh mục khác nhau về hình dạng, sau đó nó làm cho tinh thần để xác định một loại mà chính xác bắt họ:

type shapeCategory = Circular | Rectangular 

let categorize = function 
    | Circle _ -> Circular 
    | Rectangle _ -> Rectangular 

List.exists ((=) Circular) (List.map categorize a) 

a |> Seq.groupBy(categorize) 

Edit - theo đề nghị của Brian, bạn có thể lựa chọn sử dụng các mẫu tích cực thay vì của một loại mới. Nó hoạt động khá giống với các ví dụ của bạn, nhưng sẽ mở rộng tốt hơn cho các mẫu phức tạp hơn, trong khi cách tiếp cận ở trên có thể tốt hơn nếu mã của bạn thường hoạt động với các danh mục và bạn muốn có loại liên kết tốt cho chúng thay vì loại Lựa chọn .

let (|Circular|Rectangular|) = function 
    | Circle _ -> Circular 
    | Rectangle _ -> Rectangular 

List.exists (function Circular -> true | _ -> false) a 

let categorize : shape -> Choice<unit, unit> = (|Circular|Rectangular|) 
a |> Seq.groupBy(categorize) 
+7

Cách khác, một Mẫu hoạt động. – Brian

+0

Bạn có thể đưa ra một ví dụ như thế nào không? – Emile

+1

Tôi đã thêm phiên bản có Mẫu hoạt động và so sánh ngắn gọn. – RD1

8

Bạn có thể sử dụng F thư viện # phản ánh để có được thẻ của một giá trị:

let getTag (a:'a) = 
    let (uc,_) = Microsoft.FSharp.Reflection.FSharpValue.GetUnionFields(a, typeof<'a>) 
    uc.Name 

a |> Seq.groupBy getTag 
+0

Giải pháp rất hay và chung cho nhóm. Cảm ơn! – Emile

3

Tôi muốn thêm một giải pháp làm việc với các trích dẫn cho mọi trường hợp công đoàn, dựa trên một giải pháp được cung cấp. Ở đây nó đi:

open Microsoft.FSharp.Quotations.Patterns 
open Microsoft.FSharp.Reflection 

let rec isUnionCase = function 
| Lambda (_, expr) | Let (_, _, expr) -> isUnionCase expr 
| NewTuple exprs -> 
    let iucs = List.map isUnionCase exprs 
    fun value -> List.exists ((|>) value) iucs 
| NewUnionCase (uci, _) -> 
    let utr = FSharpValue.PreComputeUnionTagReader uci.DeclaringType 
    box >> utr >> (=) uci.Tag 
| _ -> failwith "Expression is no union case." 

Được xác định theo cách này, isUnionCase hoạt động như desco đã hiển thị, nhưng ngay cả trên trường hợp công đoàn trống hoặc có nhiều giá trị. Bạn cũng có thể nhập một tuple các trường hợp nghiệp đoàn được phân cách bằng dấu phẩy. Hãy xem xét điều này:

type SomeType = 
| SomeCase1 
| SomeCase2 of int 
| SomeCase3 of int * int 
| SomeCase4 of int * int * int 
| SomeCase5 of int * int * int * int 

let list = 
    [ 
     SomeCase1 
     SomeCase2 1 
     SomeCase3 (2, 3) 
     SomeCase4 (4, 5, 6) 
     SomeCase5 (7, 8, 9, 10) 
    ] 

list 
|> List.filter (isUnionCase <@ SomeCase4 @>) 
|> printfn "Matching SomeCase4: %A" 

list 
|> List.filter (isUnionCase <@ SomeCase3, SomeCase4 @>) 
|> printfn "Matching SomeCase3 & SomeCase4: %A" 

Đầu tiên làUnionCase tôi chỉ cung cấp để kiểm tra trường hợp đơn. Sau đó tôi đã thêm kiểm tra biểu thức cho NewTuple và nghĩ rằng bạn có thể thích nó. Chỉ cần chắc chắn rằng nếu bạn thay đổi mã các precomputations vẫn hoạt động, đây là lý do tại sao iucs được định nghĩa bên ngoài hàm trả về vô danh.

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