为什么`fmap(需要10个)。顺序 。 fmap return $ [1 ..] :: m [Int]`仅适用于某些单子吗?

时间:2019-07-13 15:41:45

标签: haskell

我希望拥有无穷无尽的随机或不确定数字。我继续像这样编程:

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

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

不幸的是,我不能从那笔物品中拿走任何东西。

当我将action替换为return并尝试使用不同的monad时,我发现IdentityReader可以工作,但在这种情况下它们并没有那么有用。 / p>

λ 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.

某些单子在排序时有这种挂起的性质,这一定是有原因的,但是我看不到。这是严格性问题吗?例如,此Identity和list实例之间的标志区别是什么?为什么我可以用Identity i组成一个流,却不能用类似的琐碎的单例列表[i]组成一个流?

1 个答案:

答案 0 :(得分:5)

这在IO中不起作用也就不足为奇了。您正在建立IO动作的无限列表,然后sequence将其变成单个IO动作,该动作通过执行 all 来生成整个列表基本动作。它必须立即执行所有操作,因为它们可能会有副作用。  显然,这将永远不会结束。如果您希望这样做,则需要类似unsafeInterleaveIO的东西。

[]示例更加微妙。以下内容也会挂起:

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

transpose必须遍历整个无限列表,寻找其中可能包含两个元素的任何元素来决定是否应该有第二行。 sequence基本相同。