6

解决尴尬的小队的论文中,西蒙·佩顿·琼斯提供了一个“可能的实现” Channel

type Channel a = (MVar (Stream a) , -- Read end
                  MVar (Stream a) ) -- Write end (the hole)

type Stream a = MVar (Item a)

data Item a = MkItem a (Stream a)

现在,他实现了putChan :: Channel a -> a -> IO ()这样的功能

putChan (read, write) val
  = do { new_hole <- newEmptyVar ;
         old_hole <- takeMVar write ;
         putMVar write new_hole ;
         putMVar old_hole (MkItem val new_hole) }

上面的函数从写入中取出一个 MVar,然后将一个空的 MVar 放入其中。
然后它写入从 write 中提取的 old_hole。

问题是,它为什么要写入 old_hole?它已经从 write 中取出,并且它的范围仅限于当前块,那么它有什么区别呢?

4

1 回答 1

4

问题是,它为什么要写入 old_hole?它已经从 write 中取出,并且它的范围仅限于当前块,那么它有什么区别呢?

不完全的。在读取端old_hole是“范围内” 。您必须查看完整的图片:newChan

newChan = do { 
    read <- newEmptyMVar ;
    write <- newEmptyMVar ;
    hole <- newEmptyMVar ;
    putMVar read hole ;
    putMVar write hole ;
    return (read,write) }

所以在调用newChan" old_hole" from之后putChan就和inMVar一样。随着通道操作的进展,它总是嵌套在.holenewChanold_holeMVarread

一开始我发现链表式通道的设计真的很难让我理解。那篇论文的插图在显示结构方面做得不错,但基本思想是读者“剥去”一层 MVar 以显示一个值,而作者则在 MVar 堆的“底部”插入值,维护指向最底部的指针。

顺便说一句,这是Control.Concurrent.Chan中使用的设计

于 2015-01-08T22:52:14.757 回答