Sink
s are a more flexible alternative to lazy I/O
(unsafeInterleaveIO
). Lazy I/O conflates evaluation with execution;
a value obtained from unsafeInterleaveIO
can perform side-effects
during the evaluation of pure code. Like lazy I/O, a Sink
provides a
way to obtain the value of the result of an IO
action before the
action has been executed, but unlike lazy I/O, it does not enable pure
code to perform side-effects. Instead, the value is explicitly
assigned by a later IO
action; repeated attempts to assign the value
of a Sink
fail. The catch is that this explicit assignment must
occur before the value is forced, so just like with lazy I/O, you
can't get away with completely ignoring evaluation order without
introducing bugs. However, violating this condition does not violate
purity because if the value is forced before it has been assigned, it
is .
In practice, using Sink
s instead of unsafeInterleaveIO
requires a
bit more IO
boilerplate. The main practical difference is that while
unsafeInterleaveIO
requires you to reason about effects from the
point of view of pure code, Sink
s require you to reason about
evaluation order of pure code from the point of view of IO
; the IO
portion of your program will have to be aware of what data is
necessary to produce *for* your pure code in order to be able to
consume the output it expects *from* your pure code.
- data Sink a
- newSinkMsg :: String -> IO (Sink a, a)
- newSink :: IO (Sink a, a)
- tryWriteSink :: Sink a -> a -> IO Bool
- writeSink :: Sink a -> a -> IO ()
- data MultipleWrites = MultipleWrites
Documentation
newSinkMsg :: String -> IO (Sink a, a)Source
tryWriteSink :: Sink a -> a -> IO BoolSource
writeSink :: Sink a -> a -> IO ()Source
Attempt to assign a value to a Sink
. If the Sink
had already
been written to, throw a MultipleWrites
exception. This is an
atomic (thread safe) operation.
data MultipleWrites Source