Lo que deseo tener es un suministro interminable de números que son aleatorios o no deterministas. Fui a programarlo así:

supply :: Monad m => (Int -> m Int) -> m [Int]
supply action = sequence . fmap action $ [1..]

- con action siendo \n -> randomRIO (1, n) o \n -> [1.. n]

Desafortunadamente, no pude tomar nada de esa oferta.

Cuando reemplacé action con return y probé diferentes mónadas, descubrí que Identity y Reader funcionan, pero no son tan útiles en este caso.

λ flip runReader 13 (fmap (take 10) (supply return))
[1,2,3,4,5,6,7,8,9,10]
λ runIdentity (fmap (take 10) (supply return))      
[1,2,3,4,5,6,7,8,9,10]
λ [] : (fmap (take 10) (supply return))
[[]^CInterrupted.
fmap (take 10) (supply return) :: IO [Int]
^CInterrupted.

Debe haber una razón para que algunas mónadas tengan esta calidad de colgar cuando se secuencie, pero no lo veo. ¿Es este un problema de estrictismo? ¿Cuál es la diferencia de selección, por ejemplo, entre esta identidad y la instancia de la lista? ¿Por qué puedo tener un flujo ensamblado de Identity i, pero no de las listas de singleton tan igualmente triviales [i]?

2
Ignat Insarov 13 jul. 2019 a las 18:41

1 respuesta

La mejor respuesta

No debería sorprender que esto no funcione en IO. Está construyendo una lista infinita de acciones IO, y luego sequence se convierte en una acción única IO que produce la lista completa realizando todos de la Acciones subyacentes. Debe realizar todas las acciones de inmediato porque pueden tener efectos secundarios. Claramente, esto nunca terminará. Si desea que esto funcione, necesita algo como unsafeInterleaveIO.

El ejemplo [] es un poco más sutil. Lo siguiente también va a colgar:

> map (take 10) $ transpose [[x] | x <- [1..]]
[[1,2,3,4,5,6,7,8,9,10]^CInterrupted.

transpose debe atravesar toda la lista infinita, buscando cualquier cosa que pueda tener dos elementos para decidir si debería haber una segunda fila. sequence es esencialmente el mismo.

5
Chris Smith 13 jul. 2019 a las 18:11