首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如果thunk导致异常,异常会作为thunk的结果保留吗?

如果thunk导致异常,异常会作为thunk的结果保留吗?
EN

Stack Overflow用户
提问于 2013-08-02 21:35:33
回答 1查看 492关注 0票数 16

我创建了这个小程序,它创建了一个长时间运行的thunk,最终会因异常而失败。然后,多个线程尝试计算它。

代码语言:javascript
复制
import Control.Monad
import Control.Concurrent
import Control.Concurrent.MVar

main = do
    let thunk = let p = product [1..10^4]
                 in if p `mod` 2 == 0 then error "exception"
                                      else ()
    children <- replicateM 2000 (myForkIO (print thunk))
    mapM_ takeMVar children

-- | Spawn a thread and return a MVar which can be used to wait for it.
myForkIO :: IO () -> IO (MVar ())
myForkIO io = do
     mvar <- newEmptyMVar
     forkFinally io (\_ -> putMVar mvar ())
     return mvar

增加线程的数量显然不会影响计算,这表明失败的thunk会将异常保留为结果。是真的吗?此行为是否有文档记录/在某处指定?

更新:forkFinally行更改为

代码语言:javascript
复制
forkFinally io (\e -> print e >> putMVar mvar ())

确认每个线程都失败并引发异常。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-08-04 05:08:12

让我通过使用ghc-heap-view库来说明GHC实际上是如何做到这一点的。你也许可以用ghc-vis重现这一切,并得到漂亮的照片。

我首先在某处创建一个具有异常值的数据结构:

代码语言:javascript
复制
Prelude> :script /home/jojo/.cabal/share/ghc-heap-view-0.5.1/ghci 
Prelude> let x = map ((1::Int) `div`) [1,0]

首先,它纯粹是一个thunk (似乎涉及到各种类型的类):

代码语言:javascript
复制
Prelude> :printHeap x
let f1 = _fun
in (_bco [] (_bco (D:Integral (D:Real (D:Num _fun _fun _fun _fun _fun _fun _fun) (D:Ord (D:Eq _fun _fun) _fun _fun _fun _fun _fun _fun _fun) _fun) (D:Enum _fun _fun f1 f1 _fun _fun _fun _fun) _fun _fun _fun _fun _fun _fun _fun) _fun) _fun)()

现在我评估非异常抛出部分:

代码语言:javascript
复制
Prelude> (head x, length x)
(1,2)
Prelude> System.Mem.performGC
Prelude> :printHeap x
[I# 1,_thunk (_fun (I# 1)) (I# 0)]

列表的第二个元素仍然只是一个“正常”的thunk。现在我评估一下,得到一个异常,然后再看一遍:

代码语言:javascript
复制
Prelude> last x
*** Exception: divide by zero
Prelude> System.Mem.performGC
Prelude> :printHeap x
[I# 1,_thunk (SomeException (D:Exception _fun (D:Show _fun _fun _fun) _fun _fun) DivideByZero())]

您可以看到它现在是一个引用SomeException对象的thunk。SomeException数据构造函数的类型为forall e . Exception e => e -> SomeException,因此该构造函数的第二个参数是ArithException异常的DivideByZero构造函数,第一个参数是相应的Exception类型类实例。

这个thunk可以像任何其他Haskell值一样被传递,并且如果被计算,将再次引发异常。而且,就像任何其他值一样,异常也可以共享:

代码语言:javascript
复制
Prelude> let y = (last x, last x)
Prelude> y
(*** Exception: divide by zero
Prelude> snd y
*** Exception: divide by zero
Prelude> System.Mem.performGC
Prelude> :printHeap y
let x1 = SomeException (D:Exception _fun (D:Show _fun _fun _fun) _fun _fun) DivideByZero()
in (_thunk x1,_thunk x1)

同样的事情也发生在线程和MVars上,没有什么特别的。

票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18018254

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档