2 % (c) The GRASP/AQUA Project, Glasgow University, 1995
4 \section[Channel]{Unbounded Channels}
6 Standard, unbounded channel abstraction.
11 {- abstract type defined -}
15 newChan, -- :: IO (Chan a)
18 putChan, -- :: Chan a -> a -> IO ()
19 getChan, -- :: Chan a -> IO a
20 dupChan, -- :: Chan a -> IO (Chan a)
21 unGetChan, -- :: Chan a -> a -> IO ()
23 {- stream interface -}
24 getChanContents, -- :: Chan a -> IO [a]
25 putList2Chan -- :: Chan a -> [a] -> IO ()
29 import IOBase ( IO(..) ) -- Suspicious!
34 A channel is represented by two @MVar@s keeping track of the two ends
35 of the channel contents,i.e., the read- and write ends. Empty @MVar@s
36 are used to handle consumers trying to read from an empty channel.
41 = Chan (MVar (Stream a))
44 type Stream a = MVar (ChItem a)
46 data ChItem a = ChItem a (Stream a)
51 See the Concurrent Haskell paper for a diagram explaining the
52 how the different channel operations proceed.
54 @newChan@ sets up the read and write end of a channel by initialising
55 these two @MVar@s with an empty @MVar@.
59 newChan :: IO (Chan a)
61 = newEmptyMVar >>= \ hole ->
62 newMVar hole >>= \ read ->
63 newMVar hole >>= \ write ->
64 return (Chan read write)
68 To put an element on a channel, a new hole at the write end is created.
69 What was previously the empty @MVar@ at the back of the channel is then
70 filled in with a new stream element holding the entered value and the
75 putChan :: Chan a -> a -> IO ()
76 putChan (Chan read write) val
77 = newEmptyMVar >>= \ new_hole ->
78 takeMVar write >>= \ old_hole ->
79 putMVar write new_hole >>
80 putMVar old_hole (ChItem val new_hole) >>
84 getChan :: Chan a -> IO a
85 getChan (Chan read write)
86 = takeMVar read >>= \ rend ->
87 takeMVar rend >>= \ (ChItem val new_rend) ->
88 putMVar read new_rend >>
92 dupChan :: Chan a -> IO (Chan a)
93 dupChan (Chan read write)
94 = newEmptyMVar >>= \ new_read ->
95 readMVar write >>= \ hole ->
96 putMVar new_read hole >>
97 return (Chan new_read write)
99 unGetChan :: Chan a -> a -> IO ()
100 unGetChan (Chan read write) val
101 = newEmptyMVar >>= \ new_rend ->
102 takeMVar read >>= \ rend ->
103 putMVar new_rend (ChItem val rend) >>
104 putMVar read new_rend >>
109 Operators for interfacing with functional streams.
113 getChanContents :: Chan a -> IO [a]
116 = unsafeInterleavePrimIO (
117 getChan ch `thenPrimIO` \ ~(Right x) ->
118 unsafeInterleavePrimIO (getChanContents ch) `thenPrimIO` \ ~(Right xs) ->
119 returnPrimIO (Right (x:xs)))
121 = my_2_IO $ unsafeInterleavePrimIO (
122 getChan_prim ch >>= \ ~(Right x) ->
123 unsafeInterleavePrimIO (getChanContents_prim ch) >>= \ ~(Right xs) ->
124 returnPrimIO (Right (x:xs)))
126 my_2_IO :: PrimIO (Either IOError a) -> IO a -- simple; primIOToIO does too much!
129 getChan_prim :: Chan a -> PrimIO (Either IOError a)
130 getChanContents_prim :: Chan a -> PrimIO (Either IOError [a])
132 getChan_prim ch = ST $ \ s ->
133 case (getChan ch) of { IO (ST get) ->
136 getChanContents_prim ch = ST $ \ s ->
137 case (getChanContents ch) of { IO (ST get) ->
141 putList2Chan :: Chan a -> [a] -> IO ()
142 putList2Chan ch ls = sequence (map (putChan ch) ls)