2015-12-06 17 views
6

Câu hỏi F # newbie. Tôi có một danh sách các đoàn thể phân biệt như:F # danh sách bộ lọc chức năng chung của các công đoàn bị phân biệt

type Type1 = { name:string; id: int; } 
type Type2 = { x: float; y: float;} 
type Type3 = { x: float; naam:string} 
type Union1 = 
    | T1 of Type1 
    | T2 of Type2 
    | T3 of Type3 
let lst1 = [ T1 {name="nnn"; id=3}; T2 {x=1.1; y=1.3}; T1 {name="naam1"; id=39}; T3{x=0.0; naam="xx"}]; 

//To filter out items of Type1, i do: 
let fltT1 (l:list<Union1>) :list<Type1> = 
    let rec loop (l:list<Union1>) (acc:list<Type1>) = 
     match l with 
     | h::t -> match h with 
        // this is now specific per type 
        | T1{name=n;id=i} -> loop t ({name=n;id=i}::acc) 
        | _ -> loop t acc 
     | [] -> acc 
    loop l [] |> List.rev 

Làm thế nào tôi có thể làm như vậy một hàm tổng quát để xác định trong cuộc gọi loại sản lượng yêu cầu (type1 | Type2 | Type3)?

+0

Sự cố của bạn đã được giải quyết? –

Trả lời

8

Cách tiếp cận của tôi có thể chỉ sử dụng List.choose hoặc Seq.choose. Nó có lợi thế hơn filter/map bởi vì bạn chỉ cần thực hiện khớp mẫu một lần và nó ngắn gọn hơn nhiều so với fold.

lst1 
|> List.choose 
    (function 
    |T1 res -> Some res 
    |_ > None) 

choose là một cái gì đó giống như một bản đồ và một bộ lọc kết hợp, nó sẽ trả f(x) cho mọi phần tử hiển thị kết quả đó là Some và bỏ qua tất cả các yếu tố nơi nó được None. Trong ví dụ này, kiểu trả về là Type1 list.


Không thể thực hiện được một hàm dựa trên trường hợp công đoàn cụ thể, vì trường hợp công đoàn cụ thể không phải là kiểu bản thân, chúng chỉ đơn thuần là nhà thầu cho loại công đoàn. T1 trong ví dụ của bạn không phải là một loại nhưng Union1 là. Điều đó có nghĩa là, tại một số điểm, cần phải có một kết hợp mẫu rõ ràng để phân tách nó. (Lưu ý rằng điều này không đúng với tất cả các ngôn ngữ chức năng, các trường hợp công đoàn của Scala được mô hình hóa với thừa kế nhưng F # sử dụng cách tiếp cận được sử dụng bởi các kiểu như Haskell, Ocaml, v.v.).

Như Fyodor Soikin đề cập, bạn có thể viết thành viên tĩnh hoặc một chức năng để kiểm tra đối với từng trường hợp nếu bạn muốn, như một ví dụ:

static member tryAssumeT1 = function 
    |T1 t1 -> Some t1 
    | _ -> None 

Sau đó bạn có thể sử dụng cú pháp sau:

lst1 |> List.choose (tryAssumeT1) 
+0

Cảm ơn, đó là tốt đẹp và ngắn. Nhưng có vẻ như tôi vẫn cần viết các biểu thức (hàm) riêng biệt để lọc ra các mục cho Type1, Type2 và Type3? Có thể tạo một hàm tham số với loại được yêu cầu không? – RobF

+0

Bạn có thể mã hóa nó một cách độc đáo bằng cách cung cấp các hàm truy cập cho kiểu 'Union1' của bạn, như' thành viên tĩnh t1 = hàm T1 t -> Một số t | _ -> None' và sau đó sử dụng chúng làm đối số cho 'List.choose' như' List.choose Union1.t1'. –

+0

Điều đó có hiệu quả! Nhưng lần đầu tiên tôi phải khai báo Type1 .. Type3, thì các nhà xây dựng công đoàn T1 .. T3, và chỉ sau đó thêm hàm tĩnh "phù hợp" vào loại Type1 .. Type2. Điều đó có đúng không? – RobF

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