2011-10-10 38 views
13

Hãy nói rằng tôi có một danh sách và một bộ và tôi muốn làm một số thứ với họ:F #: giết chết dư thừa trong Bản đồ/Giảm/Lọc

let outA = inA |> List.map(fun x -> x + 1) |> List.filter(fun x -> x > 10) 
let outB = inB |> Set.map(fun x -> x + 1) |> Set.filter(fun x -> x > 10) 

Bây giờ, rõ ràng Một xử lý danh sách và B xử lý bộ. Tuy nhiên, tôi thấy rất khó chịu khi phải viết List.List. nhiều lần: không chỉ là bản mẫu tiết kiệm, lặp đi lặp lại mà truyền tải không có thông tin và nhận được cách đọc chức năng của mã, nó cũng là một thực tế nhập chú thích mà tôi phải theo dõi và tiếp tục đồng bộ với phần còn lại của mã.

Những gì tôi muốn để có thể làm là một cái gì đó như sau:

let outA = inA |> map(fun x -> x + 1) |> filter(fun x -> x > 10) 
let outB = inB |> map(fun x -> x + 1) |> filter(fun x -> x > 10) 

Với trình biên dịch biết rằng Ina là một danh sách và INB là một tập hợp, và do đó tất cả các hoạt động được từ lớp đúng và do đó outA là một danh sách và outB là một tập hợp. Tôi có thể đạt được điều này một phần với Seq:

let map(x) = 
    Seq.map(x) 

let filter(x) = 
    Seq.filter(x) 

Và tôi có thể viết chính xác điều đó. Vấn đề với điều này là nó đưa mọi thứ vào Sequences, và tôi không còn có thể thực hiện các hoạt động danh sách/thiết lập trên chúng nữa. Tương tự,

let outA = inA.Select(fun x -> x + 1).Where(fun x -> x > 10) 
let outB = inB.Select(fun x -> x + 1).Where(fun x -> x > 10) 

Cũng loại bỏ tất cả điều đó, nhưng sau đó chuyển mọi thứ tới IEnumerable. Tôi quản lý để có được nó khá đẹp bằng cách chuyển đổi tất cả các phương pháp tĩnh vào phương pháp dụ thông qua phần mở rộng:

type Microsoft.FSharp.Collections.List<'a> with 
    member this.map(f) = this |> List.map(f) 
    member this.filter(f) = this |> List.filter(f) 

let b = a.map(fun x -> x + 1).filter(fun x -> x > 10) 

nhưng tôi nghi ngờ rằng sẽ gặp những vấn đề kiểu suy luận đề cập ở đây: Method Chaining vs |> Pipe Operator? Tôi không thực sự biết; Tôi không quen thuộc với cách thuật toán suy luận kiểu hoạt động.

Điểm mấu chốt là, tôi hình dung tôi sẽ làm rất nhiều công việc trong danh sách/bộ/bản đồ mảng/giảm/lọc và tôi muốn làm cho chúng trông đẹp và sạch sẽ nhất có thể. Ngay bây giờ, ngoài việc phân tâm tôi khỏi các bit quan trọng trong biểu thức (tức là "bản đồ" và lambda), chúng cũng cung cấp chú thích loại thực tế ở một nơi mà trình biên dịch nên biết rõ bộ sưu tập tôi là gì đi qua là. Hơn nữa, đây chính xác là điều mà sự thừa kế và đa hình OO có nghĩa là để giải quyết, vì vậy tôi đã tự hỏi nếu có một số mô hình chức năng tương đương mà tôi không biết rằng sẽ giải quyết nó chỉ là một cách thanh lịch. Có lẽ tôi có thể thực hiện kiểm tra kiểu trong static map tĩnh của riêng mình và thực hiện chức năng map của loại có liên quan trên đầu vào?

Có ai có bất kỳ giải pháp nào tốt hơn những gì tôi đã thử hay không, tôi có bị giới hạn cơ bản về động cơ suy luận kiểu F # không, tôi có nên chấp nhận và tiếp tục không?

+2

Theo ý kiến ​​của tôi, tên mô-đun làm cho mã mô tả hơn. Bạn biết rằng đó là một List/Set, chỉ bằng cách nhìn vào mã. – ebb

+4

Về cơ bản bạn muốn loại lớp :) Thanh toán Haskell, hoặc ở lại với chúng tôi và sử dụng tên đủ điều kiện. –

+1

@ebb: Nhưng điểm suy luận kiểu là tôi không cần mô tả mã quá nhiều = D. –

Trả lời

11

Đây không phải là giải pháp OO/kế thừa/đa hình. Thay vào đó nó là thứ 'loại lớp' (a la Haskell) giải quyết. Hệ thống kiểu .NET không có khả năng làm các lớp kiểu, và F # không cố gắng thêm khả năng đó. (Bạn có thể làm một số thủ thuật lông với inline, nhưng nó có những hạn chế khác nhau.)

Tôi khuyên bạn nên chấp nhận và tiếp tục.

+0

Tôi đang xem các lớp học ngay bây giờ. Tôi nghĩ rằng điểm của OO/Inheritance/Polymorphism là bạn có thể cho nó một tên phương thức, và nó sẽ ngay lập tức biết (dựa trên những gì bạn đưa vào như "this") * mà * phương thức để gọi (trong số nhiều lớp mà tất cả đều có phương pháp đó), mà _is_ vấn đề của tôi. Hay tôi hoàn toàn mất tích? –

+3

Ở mức cao, mô tả của bạn là đúng và có vẻ như OO sẽ làm điều này. Nhưng trong các chi tiết, các loại có phân lớp không hoạt động ... Hãy kiểm tra các loại lớp, nhưng có thể thấy "phương sai" (hiệp phương sai và đối nghịch) vì nó liên quan đến OO để có cảm giác về lý do tại sao OO không thể khá giải quyết điều này nói chung. – Brian

+2

+1, nhưng tôi nghĩ rằng hỗ trợ cho typeclasses cũng có thể được thực hiện trên .NET, nó chỉ là hệ thống kiểu F # không thực hiện điều này. – Ingo

5

Tôi đồng ý với Brian - bạn sẽ chỉ quen với việc này. Như tôi đã đề cập trong câu trả lời cho câu hỏi trước của bạn, điều này đôi khi khá hữu ích, bởi vì bạn sẽ thấy mã của bạn làm gì (phần nào đánh giá lazily, phần nào sử dụng mảng cho hiệu quả, v.v.)

Ngoài ra, một số chức năng chỉ có sẵn cho một số loại - ví dụ có List.tail hoặc List.foldBack, nhưng chức năng tương tự không tồn tại cho IEnumerable (trong module Seq) - vì lý do tốt như họ sẽ dẫn đến mã xấu . Trong Haskell, loại lớp có thể mô tả các loại có một số chức năng (như mapfilter), nhưng tôi không nghĩ rằng chúng quy mô rất tốt - để chỉ định các lớp loại cho thư viện F #, bạn sẽ kết thúc với một hệ thống phân cấp của các lớp loại chỉ định cấu trúc dữ liệu giống như danh sách, cấu trúc dữ liệu danh sách giống với các hàm giống như tailfoldBack và quá nhiều ràng buộc khác.

Bên cạnh, đối với nhiều công việc xử lý danh sách đơn giản, bạn cũng có thể sử dụng comprehensions mà cung cấp cho bạn rất nhiều cú pháp đẹp hơn (nhưng tất nhiên, nó chỉ là hữu ích cho những thứ cơ bản):

let outB = seq { for x in inA do 
        if x > 10 do yield x + 1 } 
Các vấn đề liên quan