2010-10-12 8 views
31

¿Hay una función de biblioteca disponible en Haskell para componer una función consigo mismo n veces?Función de biblioteca para componer una función consigo mismo n veces

Por ejemplo, tengo esta función:

func :: a -> a 

y yo quiero hacer esto:

func . func . func . func . func . func , ... 

(hasta n tiempos, donde n sólo se conoce en tiempo de ejecución) .

Tenga en cuenta que la función iterar no sería apropiada para lo que estoy haciendo, ya que no me preocupan los resultados intermedios.

Respuesta

49

La solución iterate está bien, o puede que como ésta: la composición de n copias de f es foldr (.) id (replicate n f).

+2

Me gusta esto porque también funciona con n == 0. –

+5

@John Las otras soluciones ('iterate' con' !! 'o' lookup. Zip') también funcionan con n == 0. Mire la [definición de iterar] (http://haskell.org/ghc/docs /6.12.1/html/libraries/base-4.2.0.0/src/GHC-List.html#iterate) y verá que comienza la lista con el caso base. –

+0

@TomMD tienes razón, mi error. Estaba pensando en una definición diferente usando 'iterate', que no es tan buena como la que proporcionaste. –

24
\xs n -> iterate func xs !! n 

no sé por qué, pero me siento como iterate es algo gente no está expuesta constantemente a la hora de aprender Haskell.

Si no te gusta !! entonces puedes usar zip y lookup como alternativa. (Algunas personas/grupos/herramientas no les gusta funciones que llaman "error" en ciertos casos, no estoy afirmando búsqueda es mejor en estos casos)

lookup n . zip [0..] . iterate func 

EDIT: Ok, por lo que entonces yo borrado revirtió la eliminación porque estoy de acuerdo con el otro respondedor: no debe descontar el uso de iterar solo porque le da más de lo que necesita.

+2

Por lo que vale, ya que 'iterate' garantiza una lista infinita, usaría' (!!) 'o' genericIndex' sobre el uso de 'lookup' con' zip'. –

+0

Sí, eso es lo que estaba diciendo sobre 'lookup' y' zip' no son mejores en estos casos. '(!!)' tiene un estigma como 'head' does (o, eso es mi impresión) –

+8

Sí, es un estigma bien merecido en mi opinión también, pero todo lo que realmente significa es que tienes que tener cuidado con el uso en los casos en que podría no aplicarse, no es que nunca deberías usarlo. Como señala Trinithis, en este caso no puede salir mal excepto cuando se pasa un índice negativo. ¡Por cierto! es en realidad una mejor opción que la búsqueda aquí: la búsqueda y el zip se repetirán para siempre en un índice negativo, buscando un resultado que no está allí, pero !! fallará inmediatamente porque sabe que los índices no pueden ser negativos. – mokus

11

No sé por qué dice que iterate no es apropiado. Es perfectamente adecuado para este propósito. (!! n) . iterate func es la composición de n copias de func.

(Alguien había publicado una respuesta similar a la del código anterior, pero él/ella parece haber eliminado.)

9

(\n -> appEndo . mconcat . replicate n . Endo) n f x

7

Soy un principiante en Haskell, actualmente en el capítulo 5 ("altas funciones de orden") de Learn You a Haskell For Great Good! por lo que aún no estoy familiarizado con las funciones que se muestran en las respuestas anteriores.Dado lo que entiendo hasta ahora, lo haría así:

applyNTimes :: Int -> (a -> a) -> a -> a 
applyNTimes n f x 
    | n == 0  = x 
    | otherwise  = f (applyNTimes (n-1) f x) 
+4

Lo único que haría diferente es la coincidencia de patrones en lugar de utilizar guardias: 'applyNTimes 0 _ x = x' y luego' applyNTimes n f x = f $ applyNTimes (n-1) f x'. En realidad, deberías poder eliminar todas las x de eso también. – MatrixFrog

+0

Esta es también una buena solución, debe recordar al lector una prueba explícita por inducción en [n]. –

+5

Tenga en cuenta que esto es estrictamente mejor que '| de lo contrario = applyNTimes (n-1) f (f x) ', porque' f' podría ser flojo. –

2

Una variación en trinithis' answer utilizando el paquete newtype, sólo por diversión:

(\n f -> under Endo (mconcat . replicate n) f) 

o libre de punto:

under Endo . (mconcat .) . replicate 
+0

Ese es un paquete genial. ¡Gracias! –

2
\n -> appEndo . foldMap Endo . replicate n 
0
iterate (f .) id !! n 

o

iterate (f .) f !! (n-1) 

dependiendo de si n == 0 está permitido.

Cuestiones relacionadas