APISTM.Queue
STM.Queue
A transactional first-in, first-out queue, unbounded or bounded, after
Haskell’s TQueue and TBQueue.
Popping from an empty queue or pushing onto a full bounded one retries, so
these operations block inside STM.atomically until another task’s commit
makes them possible. They combine with other transactions, and
STM.orElse chooses between queues:
import Async exposing (Outcome(..))
import STM
import STM.Queue as Queue
result = Async.runOutcome {
urgent = STM.atomically { Queue.unbounded () }
normal = STM.atomically { Queue.unbounded () }
STM.atomically { Queue.push normal "report"; Queue.push urgent "page" }
next = { _ -> STM.atomically { STM.orElse { Queue.pop urgent } { Queue.pop normal } } }
first = next ()
second = next ()
(first, second)
}
result == Completed ("page", "report")
The queue is two lists in separate variables, so producers and consumers
do not conflict while the front holds values; a bounded queue also splits
its free-slot count between them. A queue cannot be closed: pair it with an
STM.Var Bool and STM.orElse when consumers must learn that no more
values will come.
Queue
type Queue aSource
A queue of a values. It may be shared by any number of tasks and has no
equality or Show.
bounded
bounded : Int ->{STM} Queue aSource
An empty queue holding at most capacity values; a capacity below 1 is
treated as 1.
import Async exposing (Outcome(..))
import STM
import STM.Queue as Queue
result = Async.runOutcome { STM.atomically { queue = Queue.bounded 1; first = Queue.tryPush queue 'a'; (first, Queue.tryPush queue 'b') } }
result == Completed (True, False)
drain
drain : Queue a ->{STM} List aSource
Removes and answers every value, oldest first, without retrying.
import Async exposing (Outcome(..))
import STM
import STM.Queue as Queue
result = Async.runOutcome { STM.atomically { queue = Queue.bounded 3; Queue.push queue 1; Queue.push queue 2; values = Queue.drain queue; (values, Queue.isEmpty queue) } }
result == Completed ([1, 2], True)
isEmpty
isEmpty : Queue a ->{STM} BoolSource
Whether the queue holds no values.
import Async exposing (Outcome(..))
import STM
import STM.Queue as Queue
result = Async.runOutcome { STM.atomically { queue = Queue.unbounded (); Queue.push queue (); Queue.isEmpty queue } }
result == Completed False
peek
peek : Queue a ->{STM} aSource
The oldest value, leaving it in the queue; retries while the queue is empty.
import Async exposing (Outcome(..))
import STM
import STM.Queue as Queue
result = Async.runOutcome { STM.atomically { queue = Queue.unbounded (); Queue.push queue "a"; first = Queue.peek queue; (first, Queue.pop queue) } }
result == Completed ("a", "a")
pop
pop : Queue a ->{STM} aSource
Removes and answers the oldest value; retries while the queue is empty.
import Async exposing (Outcome(..))
import STM
import STM.Queue as Queue
result = Async.runOutcome { STM.atomically { queue = Queue.unbounded (); Queue.push queue 1; Queue.push queue 2; first = Queue.pop queue; (first, Queue.pop queue) } }
result == Completed (1, 2)
push
push : Queue a -> a ->{STM} ()Source
Adds value at the back; retries while a bounded queue is full.
import Async exposing (Outcome(..))
import STM
import STM.Queue as Queue
result = Async.runOutcome { STM.atomically { queue = Queue.unbounded (); Queue.push queue 1; Queue.push queue 2; Queue.drain queue } }
result == Completed [1, 2]
tryPeek
tryPeek : Queue a ->{STM} Maybe aSource
The oldest value if there is one, leaving it in the queue, without retrying.
import Async exposing (Outcome(..))
import Maybe exposing (Maybe(..))
import STM
import STM.Queue as Queue
result = Async.runOutcome { STM.atomically { queue = Queue.unbounded (); Queue.push queue 3; Queue.tryPeek queue } }
result == Completed (Just 3)
tryPop
tryPop : Queue a ->{STM} Maybe aSource
Removes and answers the oldest value if there is one, without retrying.
import Async exposing (Outcome(..))
import Maybe exposing (Maybe(..))
import STM
import STM.Queue as Queue
result = Async.runOutcome { STM.atomically { queue = Queue.unbounded (); Queue.push queue 1; first = Queue.tryPop queue; (first, Queue.tryPop queue) } }
result == Completed (Just 1, Nothing)
tryPush
tryPush : Queue a -> a ->{STM} BoolSource
Adds value at the back unless a bounded queue is full, answering whether
it did, without retrying.
import Async exposing (Outcome(..))
import STM
import STM.Queue as Queue
result = Async.runOutcome { STM.atomically { queue = Queue.bounded 2; added = Queue.tryPush queue "x"; (added, Queue.drain queue) } }
result == Completed (True, ["x"])
unbounded
unbounded : () ->{STM} Queue aSource
An empty queue with no capacity limit.
import Async exposing (Outcome(..))
import STM
import STM.Queue as Queue
Async.runOutcome { STM.atomically { Queue.isEmpty (Queue.unbounded ()) } } == Completed True
