2012-08-30 23 views
6

Dada una lista :: [(Foo, Bar)], me gustaría realizar un scanl1 en el Bar s, pero conservar sus Foo "etiquetas"."Mapeo" scanl

I.e. Me gustaría una función con el tipo :: [(a, b)] -> ([b] -> [c]) -> [(a, c)], de modo que pueda pasar un cursivo scanl1 como segundo argumento.

Puedo escribirlo recursivamente, pero parece que hay una manera de componer funciones de orden superior para hacer esto.

¿Esto ya es posible con las funciones estándar?

Respuesta

11

En lugar de escribir una función de orden superior insatisfactorio, se podía levantar su función de combinación para enhebrar las etiquetas Foo través de lo que aún puede utilizar scanl1, que es lo que quiere decir.

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

Ahora puede usar scanl1; llevar el original y crea qux :: Bar -> Bar -> Bar

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

keeptags es simple y scanQux es cristalina.

Por ejemplo, si

type Foo = Char 
type Bar = Int 

qux = (+) 

continuación presentamos lo mejor

*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)] 

como esperaba.

+1

¡Claro, limpio, útil! – amindfv

2

Mi amigo vino con la siguiente implementación de keeptags:

import Control.Arrow 

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

creo que sigue siendo legible.

+0

Esto es genial, limpio y simple. – amindfv