Dou*_*ira 3 monads haskell lazy-evaluation strictness conduit
我有一个f :: [a] -> b对无限列表进行操作的函数(例如take 5,takeWhile (< 100) . scanl (+) 0等等)。我想为这个函数提供由严格的单子动作(例如randomIO)生成的值。
从这个问题中,我了解到repeatandsequence技巧方法不适用于严格的单子,如下例所示:
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
Run Code Online (Sandbox Code Playgroud)
因此,我考虑在单子上下文“内部”使用该函数。我受到这个循环编程示例的启发并尝试:
let loop = do
x <- return 1
(_, xs) <- loop
return (take 5 xs, x:xs)
in fst loop :: Identity [Int]
-- Overflows the stack
Run Code Online (Sandbox Code Playgroud)
和
import Control.Monad.Fix
fst <$> mfix (\(_, xs) -> do
x <- return 1
return (take 5 xs, x:xs)) :: Identity [Int]
-- Overflows the stack
Run Code Online (Sandbox Code Playgroud)
乃至
{-# 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
Run Code Online (Sandbox Code Playgroud)
但这些都不起作用。我还尝试了一种Conduit方法,即使在这种情况下也不起作用Identity:
import Conduit
runConduitPure $ yieldMany [1..] .| sinkList >>= return . take 5
Run Code Online (Sandbox Code Playgroud)
因此我想知道:
为什么上述“循环”方法都不起作用?
如果存在一个不涉及unsafeInterleaveIO. (也许iteratee是,Arrow是?)
我在这里使用 randomIO 只是为了简化示例。在实践中,我想处理通过套接字接收的消息
如果没有 ,这是不可能的unsafeInterleaveIO。归根结底的问题是IO行动必须按顺序进行。虽然引用透明值的评估顺序并不重要,但IO操作的评估顺序可能很重要。如果你想要一个通过套接字接收到的所有消息的惰性无限列表,你必须事先通知 Haskell 在操作序列中IO适合的位置(除非你使用unsafeInterleaveIO)。
您正在寻求的抽象Arrow称为,但它也存在严格单子的正确紧缩法则ArrowLoop的问题。
乍一看,它可能看起来MonadFix(通过mdoor体现mfix) 也是一个解决方案,但深入挖掘会发现fixIO存在问题,就像loop来自一样ArrowLoop。
然而,有时动作必须一个接一个地运行的限制IO有点过分,但这就是unsafeInterleaveIO目的。引用文档
unsafeInterleaveIO允许IO延迟计算。当传递 类型的值时IO a,IO仅当需要 的值时才会执行a。
现在,即使您明确表示您不想要unsafeInterleaveIO解决方案,因为我希望能够说服您这是可行的方法,这里是:
interweavingRepeatM :: IO a -> IO [a]
interweavingRepeatM action = unsafeInterleaveIO ((:) <$> action <*> interweavingRepeatM action)
Run Code Online (Sandbox Code Playgroud)
这是随机数的工作:
ghci> import System.Random
ghci> sourceOfRandomness <- interweavingRepeatM randomIO :: IO [Integer]
ghci> take 10 sourceOfRandomness
[-2002742716261662204,7803971943047671004,-8395318556488893887,-7372674153585794391,5906750628663631621,6428130029392850107,6453903217221537923,-8966011929671667536,6419977320189968675,-1842456468700051776]
Run Code Online (Sandbox Code Playgroud)