2012-08-30 35 views
6

Đưa ra danh sách :: [(Foo, Bar)], tôi muốn thực hiện quét scan1 trên Bar s, nhưng giữ lại các thẻ "Foo"."Lập bản đồ" scanl

I.e. Tôi muốn có một hàm với kiểu :: [(a, b)] -> ([b] -> [c]) -> [(a, c)], để tôi có thể vượt qua một đối số được gọi là scanl1 làm đối số thứ hai.

Tôi có thể viết nó theo cách đệ quy, nhưng có vẻ như có cách để soạn các hàm bậc cao hơn để thực hiện việc này.

Điều này có khả thi với các chức năng chuẩn không?

Trả lời

11

Thay vì viết một chức năng bậc cao không hài lòng, bạn có thể nhấc chức năng kết hợp của bạn để luồn Foo thẻ qua vì vậy bạn vẫn có thể sử dụng scanl1, đó là những gì bạn có ý nghĩa.

keeptags :: (Bar -> Bar -> Bar) -> (Foo,Bar) -> (Foo,Bar) -> (Foo,Bar) 
keeptags g (_,b) (a',b') = (a',g b b') 

Bây giờ bạn có thể sử dụng scanl1; mất gốc qux :: Bar -> Bar -> Bar của bạn và làm

scanQux :: [(Foo,Bar)] -> [(Foo,Bar)] 
scanQux = scanl1 (keeptags qux) 

keeptags là đơn giản và scanQux là tinh thể rõ ràng.

Ví dụ, nếu

type Foo = Char 
type Bar = Int 

qux = (+) 

sau đó bạn sẽ có được

*Main> scanl1 qux [1..9] 
[1,3,6,10,15,21,28,36,45] 

*Main> zip "HELLO MUM" [1..9] 
[('H',1),('E',2),('L',3),('L',4),('O',5),(' ',6),('M',7),('U',8),('M',9)] 

*Main> scanQux $ zip "HELLO MUM" [1..9] 
[('H',1),('E',3),('L',6),('L',10),('O',15),(' ',21),('M',28),('U',36),('M',45)] 

như bạn mong đợi.

+1

Rõ ràng, sạch sẽ, hữu ích! – amindfv

2

Bạn tôi đi kèm với việc thực hiện sau đây cho keeptags:

import Control.Arrow 

keeptags g (_,b) = second (g b) 

Tôi nghĩ rằng nó vẫn còn có thể đọc được.

+0

Điều này thật tuyệt vời - sạch sẽ và đơn giản! – amindfv

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