2011-12-23 34 views
10

Tôi muốn xác định một hàm tính số phần tử trong một danh sách thoả mãn một vị đưa ra:Số phần tử trong Haskell trong phong cách pointfree

number_of_elements :: (a -> Bool) -> [a] -> Int 
    number_of_elements f xs = length (filter f xs) 

Ví dụ:

number_of_elements (==2) [2,1,54,1,2] 

nên trả lại .

Chúng tôi có thể viết nó ngắn hơn:

number_of_elements f = length . filter f 

Có thể viết nó mà không f tham số?

+3

gì bạn đang tìm kiếm được gọi là "phong cách Pointfree". Có một wiki về nó ở đây: http://www.haskell.org/haskellwiki/Pointfree. Nó dạy cho bạn tất cả các thủ thuật như cú: '((.) $ (.))' Và dấu chấm: '((.). (.))'. Mặc dù vậy, tôi sẽ không tự giới thiệu phong cách này. –

+6

Tôi khuyên bạn nên chơi xung quanh với nó một chút, để xem nó hoạt động như thế nào, nhưng bằng cách sử dụng phong cách pointfree một phần 'number_of_elements f = length. lọc f'. Đó là điều dễ đọc nhất thường. –

+6

Đây là hàm tôi hiếm khi bận tâm định nghĩa, vì 'length (filter f xs)' là, thẳng thắn, dễ đọc hơn 'number_of_elements f xs'. Sau này yêu cầu tôi tìm ra chức năng của bạn bằng cách tìm kiếm định nghĩa hàm, tài liệu hoặc suy luận nó từ loại; trong khi trước đây là một cách sử dụng kết hợp đơn giản của hai hàm tôi đã hiểu - và nó cũng ngắn hơn để viết! Tôi sẽ chỉ định nghĩa điều này như là một hàm phụ trợ trong một liên kết 'where', hoặc như một hàm mô-đun chưa được xuất hiện - và thậm chí sau đó chỉ khi nó sẽ là đối số cho các hàm khác. –

Trả lời

17

Chắc chắn nó là:

number_of_elements = (length .) . filter 
+17

Vâng, đó là phong cách vô cùng hợp lý, không thể đọc được :) –

+0

Cảm ơn, và bạn có thể giải thích tại sao '(độ dài. Bộ lọc)' hoặc '(độ dài $ bộ lọc)' sẽ không hoạt động? – vikingsteve

+1

@vikingsteve, vâng, 'chiều dài. fitler' mở rộng thành '\ x -> length (filter x)'. Ở đây 'filter x' là một hàm và bạn không thể tính toán chiều dài của một hàm, bất kể hàm đó có ý nghĩa gì. Tương tự, 'length $ filter' đang cố gắng tính toán chiều dài của hàm' filter'. – Rotsor

12

Tôi không nghĩ rằng bạn có thể nhận dễ đọc hơn so với những gì bạn đề nghị. Tuy nhiên, chỉ dành riêng cho những niềm vui của nó, bạn có thể làm điều này:

numberOfElements = (.) (.) (.) length filter 

hoặc

(.:) = (.) . (.) 
numberOfElements = length .: filter 
+3

'(. *)' Thường được gọi là '(. :)'; [lambdabot] (http://www.haskell.org/haskellwiki/Lambdabot) gọi nó là, ví dụ. – ehird

+0

@ehird thay đổi nó, cảm ơn. – is7s

+2

Tại sao không 'fmap fmap fmap'? –

7

Bạn có thể muốn đọc về Semantic Editor Combinators. Lấy result combinator từ đó:

result :: (output -> output') -> (input -> output) -> (input -> output') 
result = (.) 

Các result combinator mất một chức năng và áp dụng nó vào kết quả của chức năng khác. Bây giờ, nhìn vào các chức năng chúng ta có:

filter :: (a -> Bool) -> [a] -> [a] 
length :: [a] -> Int 

Bây giờ, length áp dụng cho [a] 's; trong đó, điều đó xảy ra, là loại kết quả của các chức năng của biểu mẫu foo :: [a] -> [a]. Vì vậy,

result length :: ([a] -> [a]) -> ([a] -> Int) 

Nhưng kết quả của filter là chính xác một chức năng [a] -> [a], vì vậy chúng tôi muốn áp dụng result length đến kết quả của filter:

number_of_elements = result (result length) filter 
+1

Tôi muốn viết lại dòng cuối cùng để cô lập SEC bao gồm (bộ phối hợp trình soạn thảo ngữ nghĩa): bộ lọc độ dài 'number_of_elements = (result.result)'. Đọc như: tính toán số lượng các phần tử bằng cách áp dụng 'length' cho kết quả của' filter'. Ở đây '(result.result)' là trình soạn thảo trình soạn thảo và 'length' là trình soạn thảo (ngữ nghĩa). Chắc chắn đọc [SEC post] (http://conal.net/blog/posts/semantic-editor-combinators). – Conal

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