2009-05-25 22 views
9

Tôi đã cố gắng để thực hiện các chức năngLẫn lộn về tách lạng bộ và điểm phong cách tự do trong Haskell

every :: (a -> IO Bool) -> [a] -> IO Bool 

đó là chủ đề cho this question. Tôi đã cố gắng thực hiện điều này mà không cần đệ quy rõ ràng. Tôi đã đưa ra mã sau đây

every f xs = liftM (all id) $ sequence $ map f xs 

Chức năng của tôi không hoạt động vì nó không phải là lười (bắt buộc trong câu hỏi), vì vậy không có upvotes ở đó :-).

Tuy nhiên, tôi không dừng ở đó. Tôi đã cố gắng thực hiện chức năng điểm miễn phí để nó sẽ ngắn hơn (và thậm chí có thể mát hơn). Kể từ khi lập luận fxs là những người cuối cùng trong biểu thức tôi chỉ bỏ chúng:

every = liftM (all id) $ sequence $ map 

Nhưng điều này không làm việc như mong đợi, trên thực tế nó đã không làm việc ở tất cả:

 
    [1 of 1] Compiling Main    (stk.hs, interpreted) 

    stk.hs:53:42: 
     Couldn't match expected type `[m a]' 
       against inferred type `(a1 -> b) -> [a1] -> [b]' 
     In the second argument of `($)', namely `map' 
     In the second argument of `($)', namely `sequence $ map' 
     In the expression: liftM (all id) $ sequence $ map 
    Failed, modules loaded: none. 

Tại sao vậy? Tôi đã có ấn tượng rằng có thể đơn giản là bỏ qua các đối số hàm sau, mà về cơ bản là những gì currying là về.

Trả lời

25

Định nghĩa của $ là

f $ x = f x 

Hãy nghĩ giải lao đầy đủ chức năng của bạn:

every f xs = (liftM (all id)) (sequence ((map f) xs)) 

và phiên bản cà ri của bạn:

every = (liftM (all id)) (sequence map) 

Như bạn thấy, đây không phải là giống hệt nhau. Bạn chỉ có thể bỏ các đối số hàm sau khi chúng là điều cuối cùng được áp dụng. Ví dụ,

f x = g c x 

thực sự là

f x = (g c) x 

và việc áp dụng (gc) để x đi kèm cuối cùng, vì vậy bạn có thể viết

f = g c 

Một mô hình với các nhà điều hành ứng dụng $ là rằng nó thường trở thành nhà điều hành thành phần. trong các phiên bản không có điểm.Điều này là do

f $ g $ x 

tương đương với

(f . g) $ x 

Ví dụ,

every f xs = liftM (all id) $ sequence $ map f xs 

có thể trở thành

every f xs = (liftM (all id) . sequence . map f) xs 

tại thời điểm đó bạn có thể thả xs:

every f = liftM (all id) . sequence . map f 

Loại bỏ đối số f là khó khăn hơn, bởi vì nó được áp dụng trước toán tử thành phần. Hãy sử dụng định nghĩa của dấu chấm từ http://www.haskell.org/haskellwiki/Pointfree:

dot = ((.) . (.)) 

Với điểm, đây là

(f `dot` g) x = f . g x 

và là chính xác những gì chúng ta cần phải làm cho mỗi hoàn toàn chỉ miễn phí:

every = (liftM (all id) . sequence) `dot` map 

Đáng buồn , do hạn chế trong hệ thống kiểu Haskell, hệ thống này cần chữ ký rõ ràng:

every :: (Monad m) => (a -> m Bool) -> [a] -> m Bool 
+2

Hoặc bạn có thể sử dụng -XNoMonomorphismRestriction và thả loại sig rõ ràng. –

+1

Argh ... định nghĩa 'chấm' trông giống như ai đó đang nhìn chằm chằm vào tôi. – gawi

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