2010-01-09 18 views
12

Soy un chico de C# tratando de enseñarme a mí mismo Haskell de las transmisiones por Internet del Canal 9 de Erik Meijer. Me encontré con un rompecabezas interesante que implicaba omitir todos los 'n' elementos de una lista usando zip y mod.¿Cómo crear una lista infinitamente repetitiva en Haskell?

every :: Int -> [a] -> [a] 
every _ [] = [] 
every n xs = [x | (x,i) <- zip xs [1..], i `mod` n == 0] 

He estado pensando que podría ser más eficiente (por muy grandes listas o arroyos) si podríamos evitar el uso de mod.

Pensé en crear perezosamente una lista repetitiva de enteros para que simplemente podamos comparar el valor de i a n.

repeatInts :: Int -> [Int] 

tal que llamar repeatInts 3 vuelve [1,2,3,1,2,3,1,2,3,1,2,3,..] ad infinitum.

Teniendo en cuenta esto, podríamos redefinir every así:

every :: Int -> [a] -> [a] 
every _ [] = [] 
every n xs = [x | (x,i) <- zip xs (repeatInts n), i == n] 

Así que mi pregunta es: ¿cómo poner en práctica repeatInts?

+0

Cf. http://stackoverflow.com/questions/2026912/how-to-get-every-nth-element-of-an-infinite-list-in-haskell –

Respuesta

17

Uso cycle:

cycle :: [a] -> [a] 

cycle lazos una lista finita en una circular, o equivalentemente, la repetición infinita de la lista original. Es la identidad en listas infinitas.

se podría definir repeatInts en términos de cycle:

*Main> let repeatInts n = cycle [1..n] 
*Main> :t repeatInts 
repeatInts :: (Num t, Enum t) => t -> [t] 
*Main> take 10 $ repeatInts 3 
[1,2,3,1,2,3,1,2,3,1] 

Para los curiosos, GHC implementa cycle con

cycle [] = errorEmptyList "cycle" 
cycle xs = xs' where xs' = xs ++ xs' 

En el lenguaje puramente funcional, esta técnica curioso es conocida como que ata el nudo, una d crea estructuras de datos cíclicos en lugar de infinitas.

Para más detalles ver

+0

Gracias, gbacon. ¡De algún modo, sabía que habría una respuesta simple! Ahora puedo profundizar en el funcionamiento de 'cycle'. –

+0

De forma un tanto extraña, 'cycle' es el estándar Haskell '98, aunque las listas cíclicas no lo son. Vea lo que dice la fuente (arriba) al respecto: puede o no obtener una lista cíclica ... –

+1

curiosamente, esta Q/A es en sí misma una instancia del problema XY. ;) saltarse cada elemento n-ésimo en una lista no debe implicar ningún 'mod', ni contar hasta el infinito. la solución adecuada parece ser con 'zip' con' (cycle $ (0 <$ [2..n]) ++ [1]) ', o mediante' iterate' con 'splitAt'. :) –

2

respuesta tardía pero también se puede escribir como t la suya:

repeatInts :: Int -> [Int] 
repeatInts 0 = [] 
repeatInts a = [1..a] ++ repeatInts a 
Cuestiones relacionadas