J'ai une fonction f :: [a] -> b
qui fonctionne sur des listes infinies (par exemple take 5
, takeWhile (< 100) . scanl (+) 0
et ainsi de suite). Je veux alimenter cette fonction avec des valeurs générées par des actions monadiques strictes (par exemple randomIO
).Utilisation de listes infinies avec des monades strictes
De this question, je l'ai appris que le repeat
et sequence
approche astuce ne fonctionne pas pour monades strictes, comme l'exemple ci-dessous montrent: au lieu
import Control.Monad.Identity
take 5 <$> sequence (repeat $ return 1) :: Identity [Int]
-- returns `Identity [1,1,1,1,1]`
-- works because Identity is non-strict
take 5 <$> sequence (repeat $ return 1) :: IO [Int]
-- returns `*** Exception: stack overflow`
-- does not work because IO is strict
Alors, je pensais à l'aide de la fonction « à l'intérieur "Le contexte monadique. Je me suis inspiré par ce circular programming example et essayé:
let loop = do
x <- return 1
(_, xs) <- loop
return (take 5 xs, x:xs)
in fst loop :: Identity [Int]
-- Overflows the stack
et
import Control.Monad.Fix
fst <$> mfix (\(_, xs) -> do
x <- return 1
return (take 5 xs, x:xs)) :: Identity [Int]
-- Overflows the stack
et même
{-# LANGUAGE RecursiveDo #-}
import System.Random
loop' = mdo
(xs', xs) <- loop xs
return xs'
where loop xs = do
x <- randomIO
return (take 5 xs, x:xs)
print $ loop'
-- Returns a list of 5 identical values
Mais aucune de ces œuvres. J'ai essayé aussi une approche Conduit
qui ne fonctionne pas non plus, même dans le cas Identity
:
import Conduit
runConduitPure $ yieldMany [1..] .| sinkList >>= return . take 5
Par conséquent, je voudrais savoir:
Pourquoi aucune des approches « circulaire » au-dessus de travail?
S'il existe une solution à cela qui n'implique pas
unsafeInterleaveIO
. (peut-êtreiteratee
s,Arrow
s?)
En général, c'est un problème difficile. Pour les nombres aléatoires en particulier, il y a un moyen facile de sortir: 'randoms <$> newStdGen :: Random a => IO [a]' est une liste aléatoire infinie de ce que vous voulez (c'est 'Random'). – Alec
@Alec Merci pour le commentaire. J'utilise 'randomIO' ici juste pour la simplicité des exemples. En pratique, je voudrais traiter les messages reçus via les sockets. –
Donc quelque chose comme la liste infinie des messages reçus d'une socket? – Alec