Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Exception 如果thunk导致异常,那么异常是否作为thunk的结果保留?_Exception_Haskell_Lazy Evaluation_Thunk - Fatal编程技术网

Exception 如果thunk导致异常,那么异常是否作为thunk的结果保留?

Exception 如果thunk导致异常,那么异常是否作为thunk的结果保留?,exception,haskell,lazy-evaluation,thunk,Exception,Haskell,Lazy Evaluation,Thunk,我创建了这个小程序,它创建了一个长时间运行的thunk,最终由于异常而失败。然后,多个线程尝试对其进行评估 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"

我创建了这个小程序,它创建了一个长时间运行的thunk,最终由于异常而失败。然后,多个线程尝试对其进行评估

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

确认每个线程都出现异常失败。

让我通过展示GHC如何使用库来回答这个问题。你可能可以复制这一点,并得到很好的图片

我首先创建一个数据结构,其中包含一个异常值:

Prelude> :script /home/jojo/.cabal/share/ghc-heap-view-0.5.1/ghci 
Prelude> let x = map ((1::Int) `div`) [1,0]
起初,它纯粹是一个thunk(似乎涉及各种类型类):

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

Prelude> (head x, length x)
(1,2)
Prelude> System.Mem.performGC
Prelude> :printHeap x
[I# 1,_thunk (_fun (I# 1)) (I# 0)]
列表的第二个元素仍然只是一个“正常”的重击。现在我对其进行评估,得到一个异常,然后再次查看:

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())]
您可以看到它现在是引用对象的thunk。
SomeException
数据构造函数的类型为所有e。异常e=>e->SomeException,因此构造函数的第二个参数是
ArithException
异常的构造函数,第一个参数是对应的类型类实例

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

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)

线程和MVAR也会发生同样的情况,没有什么特别之处。

表达式的值是个例外。多次计算表达式还能做什么?@Carl这是我怀疑的,但我想确定一下。它还可以一次又一次地重新计算该值。我确实知道GHC的内部结构,否则我无法创建像
GHC heap view
这样的工具,因此我不确定您还需要什么。如果我的回答不够有用,你能澄清一下你的问题吗?@JoachimBreitner你的回答很有用,我立即投了赞成票。你的答案似乎是基于观察(我不知道你创建了ghc堆视图),我想看到的是,一些ghc黑客说“是的,ghc总是这样工作,这是它的保证行为。”如果没有这样的答案,我很乐意把赏金奖励给你。在语言层面上没有这样的保证。我很有信心GHC总是以这种方式工作——但有保证吗?我认为GHC对纯项的计算没有任何保证,可以自由复制和计算。
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())]
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)