我已经看到它用于编程(特别是在C++领域)并且不知道它是什么.据推测它是一种设计模式,但我可能是错的.谁能举出一个很好的例子?
GHC如何处理多个线程(显式线程或评估spark的内部线程)访问的thunk?是否会发生多个线程评估同一个thunk,重复工作?或者,如果thunks同步,如何,这样性能不会受到影响?
我一直在玩Simon Marlow关于Haskell中的并行和并发编程的书中的一些例子,偶然发现了一个我不太了解的有趣行为.这真的是我试图了解GHC的一些内部运作方式.
假设我在REPL中执行以下操作:
?» let x = 1 + 2 :: Int
?» let z = (x,x)
?» :sprint x
x = _
?» :sprint z
z = (_,_)
?» seq x ()
()
?» :sprint z
z = (3,3)
Run Code Online (Sandbox Code Playgroud)
好吧,这几乎是我的预期,除了z已经被评估为WHNF.让我们编写一个类似的程序并将其放在一个文件中:
module Thunk where
import Debug.Trace
x :: Int
x = trace "add" $ 1 + 2
z :: (Int,Int)
z = (x,x)
Run Code Online (Sandbox Code Playgroud)
在GHCi中摆弄它:
?» :sprint x
x = _
?» :sprint z
z = _
?» seq x () …
Run Code Online (Sandbox Code Playgroud) Haskell堆中以下值/表达式/函数的thunk是什么样的?
val = 5 -- is `val` a pointer to a box containing 5?
add x y = x + y
result = add 2 val
main = print $ result
Run Code Online (Sandbox Code Playgroud)
考虑到它的惰性评估模式,可以很好地了解这些在Haskell中的表示方式.
假设我有一个非常大的数字(数百万/十亿+)这些简单的Foo
数据结构:
data Foo = Foo
{ a :: {-# UNPACK #-}!Int
, b :: Int
}
Run Code Online (Sandbox Code Playgroud)
随着这么多的浮动,有必要考虑他们消耗多少内存.
在64位机器上,每个Int
都是8个字节,因此a
只需要8个字节(因为它是严格的和解压缩的).但是会b
占用多少内存?我想这会根据thunk是否被评估而改变,对吧?
我想在一般情况下这是不可能的,因为b
可能依赖于任何数量的内存位置,只有在b
需要评估的情况下才会留在内存中.但是,如果b
只依赖(一些非常昂贵的操作)a
呢?那么,是否有一种确定性的方式来判断将使用多少内存?
有关于它们的维基文章:(http://en.wikipedia.org/wiki/Futures_and_promises,http://en.wikipedia.org/wiki/Thunk_ ( delayed_computation)).但我不确定三者作为编程语言概念之间的确切差异是什么?期货和承诺只适用于并发编程吗?
在Haskell中,是否可以测试一个值是否已被评估为弱头正常形式?如果一个函数已经存在,我希望它有一个像这样的签名
evaluated :: a -> IO Bool
Run Code Online (Sandbox Code Playgroud)
有一些类似功能的地方.
一个以前的答案给我介绍:sprint
ghci的命令,该命令将打印已经被迫弱头部正常形态的值只有部分.:sprint
可以观察是否已评估某个值:
> let l = ['a'..]
> :sprint l
l = _
> head l
'a'
> :sprint l
l = 'a' : _
Run Code Online (Sandbox Code Playgroud)
有可能IO
检查本来是禁止的属性.例如,可以比较IO
以查看两个值是否来自同一声明.这是由StableName
s in提供System.Mem.StableName
并用于解决数据统一中的可观察共享问题.相关内容StablePtr
未提供检查引用值是否为弱头正常形式的机制.
我创建了这个小程序,它创建了一个长时间运行的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 …
Run Code Online (Sandbox Code Playgroud) 我想知道为什么在这种情况下的:sprint
报告xs = _
:
Prelude> xs = map (+1) [1..10]
Prelude> length xs
10
Prelude> :sprint xs
xs = _
Run Code Online (Sandbox Code Playgroud)
但在这种情况下不是:
Prelude> xs = map (+1) [1..10] :: [Int]
Prelude> length xs
10
Prelude> :sprint xs
xs = [_,_,_,_,_,_,_,_,_,_]
Run Code Online (Sandbox Code Playgroud)
注:我正在ghci
用-XNoMonomorphismRestriction
.是否与xs
第一种情况下的多态性类型有关,而在第二种情况下不是多态性的事实?我想知道内部发生了什么.
我对Haskell很陌生,我试图围绕Fibonacci序列的懒惰表达如何工作.
我知道之前已经问过这个问题,但是没有一个答案解决了我在查看结果时遇到的问题.
代码是使用的规范 zipWith
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
Run Code Online (Sandbox Code Playgroud)
我理解以下内容:
zipWith
字面上将两个列表拉到一起tail
抓取除列表的第一个元素之外的所有元素thunks
.从我的理解,它首先添加[0,1,<thunk>]
和[1,<thunk>]
使用zipWith (+)
给予[1,<thunk>]
.所以现在你有
fibs = 0 : 1 : 1 : zipWith (+) fibs (tail fibs)
Run Code Online (Sandbox Code Playgroud)
我用谷歌搜索过的很多参考文献都开始将上面的线"可视化"为
fibs = 0 : 1 : 1 : zipWith (+) [1,1,<thunk>] ([1,<thunk>]).
Run Code Online (Sandbox Code Playgroud)
我的问题是:
为什么 fibs
上面一行中 的组件只对应[1,1,<thunk>]
而不是 [0,1,1,<thunk>]
?
不应该fibs
包含整个列表加<thunk>
?
haskell functional-programming fibonacci lazy-evaluation thunk