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 ()
30 import IOBase ( IO(..) ) -- Suspicious!
35 A channel is represented by two @MVar@s keeping track of the two ends
36 of the channel contents,i.e., the read- and write ends. Empty @MVar@s
37 are used to handle consumers trying to read from an empty channel.
42 = Chan (MVar (Stream a))
45 type Stream a = MVar (ChItem a)
47 data ChItem a = ChItem a (Stream a)
52 See the Concurrent Haskell paper for a diagram explaining the
53 how the different channel operations proceed.
55 @newChan@ sets up the read and write end of a channel by initialising
56 these two @MVar@s with an empty @MVar@.
60 newChan :: IO (Chan a)
62 = newEmptyMVar >>= \ hole ->
63 newMVar hole >>= \ read ->
64 newMVar hole >>= \ write ->
65 return (Chan read write)
69 To put an element on a channel, a new hole at the write end is created.
70 What was previously the empty @MVar@ at the back of the channel is then
71 filled in with a new stream element holding the entered value and the
76 putChan :: Chan a -> a -> IO ()
77 putChan (Chan read write) val
78 = newEmptyMVar >>= \ new_hole ->
79 takeMVar write >>= \ old_hole ->
80 putMVar write new_hole >>
81 putMVar old_hole (ChItem val new_hole) >>
85 getChan :: Chan a -> IO a
86 getChan (Chan read write)
87 = takeMVar read >>= \ rend ->
88 takeMVar rend >>= \ (ChItem val new_rend) ->
89 putMVar read new_rend >>
93 dupChan :: Chan a -> IO (Chan a)
94 dupChan (Chan read write)
95 = newEmptyMVar >>= \ new_read ->
96 readMVar write >>= \ hole ->
97 putMVar new_read hole >>
98 return (Chan new_read write)
100 unGetChan :: Chan a -> a -> IO ()
101 unGetChan (Chan read write) val
102 = newEmptyMVar >>= \ new_rend ->
103 takeMVar read >>= \ rend ->
104 putMVar new_rend (ChItem val rend) >>
105 putMVar read new_rend >>
110 Operators for interfacing with functional streams.
114 getChanContents :: Chan a -> IO [a]
117 = unsafeInterleavePrimIO (
118 getChan ch `thenPrimIO` \ ~(Right x) ->
119 unsafeInterleavePrimIO (getChanContents ch) `thenPrimIO` \ ~(Right xs) ->
120 returnPrimIO (Right (x:xs)))
122 = my_2_IO $ unsafeInterleavePrimIO (
123 getChan_prim ch >>= \ ~(Right x) ->
124 unsafeInterleavePrimIO (getChanContents_prim ch) >>= \ ~(Right xs) ->
125 returnPrimIO (Right (x:xs)))
127 my_2_IO :: PrimIO (Either IOError a) -> IO a -- simple; primIOToIO does too much!
130 getChan_prim :: Chan a -> PrimIO (Either IOError a)
131 getChanContents_prim :: Chan a -> PrimIO (Either IOError [a])
133 getChan_prim ch = ST $ \ s ->
134 case (getChan ch) of { IO (ST get) ->
137 getChanContents_prim ch = ST $ \ s ->
138 case (getChanContents ch) of { IO (ST get) ->
142 putList2Chan :: Chan a -> [a] -> IO ()
143 putList2Chan ch ls = sequence (map (putChan ch) ls)