Shi*_* Wu 10 monads continuations haskell
我正在尝试Cont monad,并发现以下问题.
代码如下所示:
let inff = map (return :: a -> Cont r a) [0..]
let seqf = sequence inff
runCont seqf head
Run Code Online (Sandbox Code Playgroud)
那么这是Haskell中Cont monad实现的限制吗?如果是这样,我们如何改善这一点?
Pet*_*lák 13
其原因是,即使值的头元素sequence someList
只取决于第一elemenent someList
,该效果的sequence someList
一般可以依靠的全部效应someList
(以及它对于大多数的单子).因此,如果我们想要评估head元素,我们仍然需要评估所有效果.
例如,如果我们有一个列表Maybe
值,结果sequence someList
是Just
只有当所有的元素someList
都Just
.因此,如果我们尝试sequence
无限列表,我们需要检查其无限数量的元素,如果它们都是Just
.
这同样适用Cont
.在continuation monad中,我们可以随时从计算中转义并返回与到目前为止计算的结果不同的结果.请考虑以下示例:
test :: (Num a, Enum a) => a
test = flip runCont head $
callCC $ \esc -> do
sequence (map return [0..100] ++ [esc [-1]])
Run Code Online (Sandbox Code Playgroud)
或直接使用cont
而不是callCC
:
test' :: (Num a, Enum a) => a
test' = flip runCont head $
sequence (map return [0..100] ++ [cont (const (-1))])
Run Code Online (Sandbox Code Playgroud)
结果test
就是-1
.在处理前100个元素之后,最终元素可以决定逃避所有这些并返回-1
.所以为了看看是什么head
元素sequence someList
中Cont
,我们再次需要计算所有.
这不是Cont
monad 的缺陷sequence
.您可以获得类似的结果Either
,例如:
import Control.Monad.Instances ()
xs :: [Either a Int]
xs = map Right [0..] -- Note: return = Right, for Either
ys :: Either a [Int]
ys = sequence xs
Run Code Online (Sandbox Code Playgroud)
ys
在计算整个列表之前,您无法检索任何元素,这将永远不会发生.
另外,请注意:sequence (map f xs) = mapM f xs
,因此我们可以将此示例简化为:
>>> import Control.Monad.Instances
>>> mapM Right [0..]
<Hangs forever>
Run Code Online (Sandbox Code Playgroud)
有一些monad mapM
将在无限的值列表中工作,特别是懒惰的StateT
monad和Identity
,但它们是规则的例外.
通常,mapM
/ sequence
/ replicateM
(没有尾随下划线)是反模式并且使用正确的解决方案pipes
,这允许您构建有效的流,而不是尝试预先计算所有结果. 本pipes
教程的开头部分描述了如何更详细地解决这个问题,但一般的经验法则是,每当你写下这样的内容时:
example1 = mapM f xs
example2 = sequence xs
Run Code Online (Sandbox Code Playgroud)
只需将其转换为以下内容即可将其转换为惰性Producer
:
example1' = each xs >-> Pipes.Prelude.mapM f
example2' = each xs >-> Pipes.Prelude.sequence
Run Code Online (Sandbox Code Playgroud)
使用上面的例子Either
,你会写:
>>> import Pipes
>>> let xs = each [0..] >-> mapM Right :: Producer Int (Either a) ()
Run Code Online (Sandbox Code Playgroud)
然后你可以懒惰地处理流而不生成所有元素:
>>> Pipes.Prelude.any (> 10) xs
Right True
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
303 次 |
最近记录: |