2013-05-21 26 views
15

Đôi khi bạn muốn gấp một danh sách các bộ dữ liệu thành một bộ bằng các hàm gấp khác nhau. Ví dụ, để dán cùng một danh sách các kết quả runState, nhận được một trạng thái kết hợp (theo một nghĩa nào đó) và kết quả kết hợp.Sử dụng các mũi tên để gấp một danh sách các bộ dữ liệu

Xem xét việc thực hiện sau đây:

wish :: (a -> a' -> a) -> (b -> b' -> b) -> (a,b) -> [(a', b')] -> (a,b) 
wish lfn rfn x xs = foldl (\(a,b) -> (lfn a) *** (rfn b)) x xs 

Mặc dù nó hoạt động, tôi cảm thấy không thoải mái về lambda này. lfn *** rfn của chính nó có một loại (a,b) -> (a -> a', b -> b'), mà tôi không thể tìm thấy một cách để áp dụng đúng cho một bộ túp mà không bao giờ phải dùng đến mẫu phù hợp. Có một cách rõ ràng và thanh lịch tôi đang thiếu? Nó có thể là một chức năng thư viện kiểu (a,a') -> (a -> a, a' -> a') -> (a, a') hoặc một cách tiếp cận hoàn toàn khác, có thể.

+2

Một số loại lớp BiApplicative sẽ làm .. Có thể là một nơi nào đó trên hackage, nhưng tôi sẽ để nó cho người khác để trang trải cái nào tốt và không được chấp nhận. – Carl

+0

http://squing.blogspot.com/2008/11/beautiful-folding.html và diễn giải của nó trên Hackage, http://hackage.haskell.org/package/ZipFold –

Trả lời

9

Control.Arrow không chú ý nhiều đến các hàm có mức độ cao hơn. Những gì bạn thực sự muốn là một hàm foo :: (a -> a' -> a'') -> (b -> b' -> b'') -> (a,b) -> (a',b') -> (a'',b''), tương tự của (***) cho các chức năng của tính chất 2. Có một hàm như vậy trong Data.Biapplicative (từ gói bifunctor), có chữ ký có phần tổng quát hơn biliftA2 :: Biapplicative w => (a -> b -> c) -> (d -> e -> f) -> w a d -> w b e -> w c f. Vì có một cá thể Biapplicative cho các phần tử hai phần tử, đó là tất cả những gì bạn cần.

Khiếu nại duy nhất tôi có thể thấy chống lại mã của bạn vì nó đứng là nó currying của lambda là không rõ ràng; Tôi có thể thích rõ ràng hơn \(a,b) (a',b') -> (lfn a a', rfn b b').

Chỉnh sửa ghi chú: Tôi đã kết luận rằng chức năng cần thiết không tồn tại và đề xuất xác định nó; được thúc đẩy bởi bình luận của Carl, tôi tìm thấy một trong Biapplicative (chữ ký kiểu tổng quát hơn đã ngăn cản Hoogle tìm thấy nó dưới chữ ký gợi ý của tôi).

+0

Đi để phân tách thủ công bằng '\ (a , b) (a ', b') -> ... 'kinda thách thức toàn bộ mục đích của việc sử dụng một số khái niệm lạ mắt để viết một lớp lót mạnh mẽ. Cảm ơn vì đã đề cập đến Biapplicative, tôi sẽ xem xét nó. –

+0

Quan điểm của tôi là mặc dù Biapplicative's '(<<**>>)' có kiểu bạn cần áp dụng '(lfn *** rfn)', việc gọi mũi tên dường như không phù hợp với tôi ở đây. Nhưng đó chỉ là trực giác của tôi; cách tiếp cận dựa trên mũi tên là chính xác, nếu không nhất thiết phải rõ ràng. Nhưng tôi thích '(lfn \' biLiftA2 \ 'rfn)' đối với lambda rõ ràng. – isturdy