2010-06-26 28 views
13

Tôi đã chơi đùa với Haskell một chút công bằng, bao gồm thực hành các chức năng viết theo dạng không có điểm. Dưới đây là một ví dụ về chức năng:Tại sao phiên bản pointfree của chức năng này trông như thế này?

dotProduct :: (Num a) => [a] -> [a] -> a 
dotProduct xs ys = sum (zipWith (*) xs ys) 

Tôi muốn viết hàm này ở dạng không có điểm. Dưới đây là một ví dụ tôi tìm thấy ở nơi khác:

dotProduct = (sum .) . zipWith (*) 

Tuy nhiên, tôi không hiểu tại sao các hình thức điểm-miễn phí trông giống như (sum .) . zipWith (*) thay vì sum . zipWith (*). Tại sao tổng trong ngoặc đơn và có 2 toán tử thành phần?

Trả lời

19
dotProduct xs ys = sum (zipWith (*) xs ys)    -- # definition 

dotProduct xs = \ys -> sum (zipWith (*) xs ys)  -- # f x = g <=> f = \x -> g 
       = \ys -> (sum . (zipWith (*) xs)) ys -- # f (g x) == (f . g) x 
       = sum . (zipWith (*) xs)    -- # \x -> f x == f 
       = sum . zipWith (*) xs    -- # Precedence rule 

dotProduct  = \xs -> sum . zipWith (*) xs   -- # f x = g <=> f = \x -> g 
       = \xs -> (sum .) (zipWith (*) xs)  -- # f * g == (f *) g 
       = \xs -> ((sum .) . zipWith (*)) xs -- # f (g x) == (f . g) x 
       = (sum .) . zipWith (*)    -- # \x -> f x == f 

Các (sum .) là một phần. Nó được định nghĩa là

(sum .) f = sum . f 

Bất kỳ toán tử nhị phân nào cũng có thể được viết như thế này, ví dụ: map (7 -) [1,2,3] == [7-1, 7-2, 7-3].

+0

Có phải '*' trong phần này 'f * g == (f *) g' giống với thành phần hàm' .' không? – guhou

+0

@Bleu: Có. Bất kỳ toán tử nhị phân nào cũng sẽ thực hiện. – kennytm

13

câu trả lời KennyTM là tuyệt vời, nhưng tôi vẫn muốn cung cấp một quan điểm:

dotProduct = (.) (.) (.) sum (zipWith (*)) 
  • (.) f g áp dụng f trên kết quả của g cho một đối số
  • (.) (.) (.) f g áp dụng f trên kết quả của g được cho hai đối số
  • (.) (.) ((.) (.) (.)) f g áp dụng f trên kết quả của g cho ba đối số
  • ...
  • thể làm (.~) = (.) (.) (.), (.~~) = (.) (.) (.~), (.~~~) = (.) (.) (.~~) và bây giờ let foo a b c d = [1..5]; (.~~~) sum foo 0 0 0 0 kết quả trong 15.
    • Nhưng tôi sẽ không làm điều đó. Nó có thể sẽ làm cho mã không đọc được. Chỉ cần được điểm đầy đủ.
  • Conal's TypeCompose cung cấp một từ đồng nghĩa cho (.) được gọi là result. Có lẽ tên này hữu ích hơn cho việc hiểu những gì đang xảy ra.
    • fmap cũng làm việc thay vì (.), nếu nhập khẩu các trường hợp có liên quan (import Control.Applicative sẽ làm điều đó) nhưng kiểu của nó là tổng quát hơn và do đó có lẽ khó hiểu hơn.
  • Khái niệm "hợp nhất" của Conal (không bị nhầm lẫn với các tập quán khác của "phản ứng tổng hợp") là loại liên quan và imho cung cấp một cách hay để soạn các hàm. Chi tiết khác trong this long Google Tech Talk that Conal gave
+0

Cảm ơn bạn đã trả lời! Tôi vẫn còn khá mới với Haskell, do đó, một số điều này trông..arcane .. nhưng học về cách tiếp cận khác nhau là hữu ích quá :) – guhou

+2

Trường hợp '(.) (.) (.)' Là phổ biến và đơn giản, đủ mà tôi đôi khi tạo một '(...) 'toán tử cho nó. Ngoài ra, mặc dù, nó có lẽ là thời gian để được điểm. –

+1

quá tệ '..' được lấy: D –

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