2013-01-16 40 views
8

tôi tiếp tục tái sử dụng các biểu thức lambda nhưPointfree (hoặc thư viện) chức năng để áp dụng hai chức năng để đơn đầu vào

\x -> (f x, g x) 

nơi tôi áp dụng các đầu vào tương tự cho hai chức năng và đóng gói các kết quả trong một cặp. Tôi có thể viết một chức năng để chụp ảnh này

combine :: (a -> b) -> (a -> c) -> a -> (b,c) 
combine f g x = (f x, g x) 

Bây giờ biểu thức lambda ở trên chỉ là combine f g. Tôi có hai câu hỏi.

  1. Tôi muốn biết liệu có chức năng thư viện chuẩn thực hiện điều này mà tôi không thể tìm thấy.
  2. Ngoài sự tò mò, tôi muốn viết lại chức năng này theo kiểu không có điểm, nhưng tôi đang gặp nhiều rắc rối với nó.

Trả lời

12
  1. Control.Arrow có chức năng (&&&) cho việc này. Nó có loại "tổng quát hơn", thật không may có nghĩa là Hoogle không tìm thấy nó (có thể đây sẽ được coi là một lỗi trong Hoogle?).

  2. Bạn thường có thể tự động định hình loại điều này với pointfree, trong đó lambdabot trong #haskell có dạng plugin.

Ví dụ:

<shachaf> @pl combine f g x = (f x, g x) 
<lambdabot> combine = liftM2 (,) 

đâu liftM2 với (r ->) thể hiện của Monad đã gõ (a -> b -> c) -> (r -> a) -> (r -> b) -> r -> c. Tất nhiên, có rất nhiều cách viết khác, miễn phí, tùy thuộc vào những gì bạn cho phép.

+0

Cảm ơn cho câu trả lời ngắn gọn, và nhờ chỉ cho tôi đến pointfree. – bshourd

12

Tôi muốn biết liệu có chức năng thư viện chuẩn thực hiện điều này mà tôi không thể tìm thấy.

Rất dễ bỏ lỡ vì loại lớp, nhưng look at Control.Arrow. Đồng bằng Arrow s không thể được quấy rầy hoặc áp dụng, do đó, các bộ phối hợp Arrow là vô nghĩa bởi sự cần thiết. Nếu bạn chuyên họ (->), bạn sẽ tìm thấy một trong những bạn muốn là thế này:

(&&&) :: (Arrow a) => a b c -> a b c' -> a b (c, c') 

Có khác, chức năng tương tự, chẳng hạn như các hoạt động tương đương cho Either, chuyên để (->) trông như thế này:

(|||) :: (a -> c) -> (b -> c) -> Either a b -> c 

Tương tự như either.

Ngoài sự tò mò, tôi muốn viết lại hàm này theo kiểu không có điểm, nhưng tôi đang gặp nhiều rắc rối với nó.

Vì bạn đang sao chép một đầu vào, bạn cần một số cách để làm điều pointfree đó - cách phổ biến nhất là thông qua các Applicative hoặc Monad dụ cho (->), ví dụ \f g ->(,) < $ > f < *> g . Đây thực chất là một nội dung đơn giản, nội tuyến Reader và đối số được phân tách là giá trị "môi trường". Sử dụng phương pháp này, join f x trở thành f x x, pure hoặc return trở thành const, fmap trở thành (.), và (<*>) trở thành S combinator\f g x -> f x (g x).

+2

Một phần lý do khiến các chức năng của Control.Arrow khó bỏ qua là Hoogle sẽ không hợp nhất các biến kiểu với '->', ngay cả khi loại so khớp, vì vậy [Hoogling cho '(a -> b) -> (a -> c) -> a -> (b, c) '] (http://www.haskell.org/hoogle/?q= (a + -% 3E + b) + -% 3E + (a + -% 3E + c) + -% 3E + a + -% 3E + (b% 2Cc)) không tìm thấy '(&&&)'. ([Hoogling cho 'fab -> fac -> fa (b, c)'] (http://www.haskell.org/hoogle/?q=f+a+b+-%3E+f+a+c+- % 3E + f + a + (b% 2Cc) hoạt động, cũng như (với cảnh báo) [Hoogling cho '(a ~> b) -> (a ~> c) -> (a ~> (b, c)) '] (http://www.haskell.org/hoogle/?hoogle=%28a+~%3E+b%29+-%3E+%28a+~%3E+c%29+-%3E+a+~%3E+% 28b% 2Cc% 29)) –

+1

Cảm ơn cả hai vì điều này, đây chính xác là những gì tôi muốn biết.Cảm ơn Antal đã chỉ ra cú pháp 'a ~> b' cho Hoogle, mà tôi không biết. – bshourd

6

Thực tế, có một số cách để thực hiện việc này. Cách phổ biến nhất là sử dụng (&&&) chức năng từ Control.Arrow:

f &&& g 

Tuy nhiên, thường bạn có nhiều chức năng hay cần phải vượt qua kết quả chức năng khác, trong trường hợp này nó là thuận tiện hơn nhiều để sử dụng phong cách applicative. Sau đó

uncurry (+) . (f &&& g) 

trở thành

liftA2 (+) f g 

Như đã nói điều này có thể được sử dụng với nhiều hơn một chức năng:

liftA3 zip3 f g h 
+0

Cảm ơn Đặc biệt là đối với lời giải thích "sử dụng nhiều hơn một hàm" – bshourd

+1

Và tất nhiên, những điều này có thể được viết lại bằng '<$>' và '<*>': 'zip3 <$> f <*> g <*> h'. Đôi khi điều này rõ ràng hơn là sử dụng' liftA * '. –

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