Non Blocking Channel Operations in PureScript
Here’s the PureScript translation of the non-blocking channel operations example:
module Main where
import Prelude
import Effect (Effect)
import Effect.Console (log)
import Control.Monad.Rec.Class (forever)
import Effect.Aff (Aff, launchAff_, makeAff, nonCanceler)
import Effect.Aff.AVar (AVar)
import Effect.Aff.AVar as AVar
main :: Effect Unit
main = launchAff_ do
messages <- AVar.empty
signals <- AVar.empty
-- Here's a non-blocking receive. If a value is
-- available on `messages` then it will be taken.
-- If not, it will immediately take the default case.
tryReceive messages "no message received"
-- A non-blocking send works similarly. Here `msg`
-- cannot be sent to the `messages` channel, because
-- the channel has no buffer and there is no receiver.
-- Therefore the default case is selected.
let msg = "hi"
trySend messages msg "no message sent"
-- We can use multiple cases to implement a multi-way
-- non-blocking select. Here we attempt non-blocking
-- receives on both `messages` and `signals`.
tryMultiReceive messages signals "no activity"
tryReceive :: AVar String -> String -> Aff Unit
tryReceive avar defaultMsg = do
result <- AVar.tryTake avar
case result of
Just msg -> log $ "received message " <> msg
Nothing -> log defaultMsg
trySend :: AVar String -> String -> String -> Aff Unit
trySend avar msg defaultMsg = do
result <- AVar.tryPut msg avar
if result
then log $ "sent message " <> msg
else log defaultMsg
tryMultiReceive :: AVar String -> AVar Boolean -> String -> Aff Unit
tryMultiReceive messages signals defaultMsg = do
result <- makeAff \cb -> do
void $ AVar.tryTake messages >>= case _ of
Just msg -> cb (Right (Left msg))
Nothing -> pure unit
void $ AVar.tryTake signals >>= case _ of
Just sig -> cb (Right (Right sig))
Nothing -> pure unit
cb (Right (Left defaultMsg))
pure nonCanceler
case result of
Left msg -> log $ "received message " <> msg
Right sig -> log $ "received signal " <> show sig
In this PureScript translation, we use AVar
(asynchronous variables) from the purescript-aff
library to simulate channels. The tryTake
and tryPut
functions on AVar
provide non-blocking operations similar to the select statements in the original example.
The tryReceive
, trySend
, and tryMultiReceive
functions implement the non-blocking channel operations. They use pattern matching and the Maybe
type to handle the presence or absence of values, similar to the select statements in the original code.
Note that PureScript doesn’t have built-in channels or a direct equivalent to Go’s select
statement. The makeAff
function is used in tryMultiReceive
to create a custom asynchronous effect that attempts to receive from multiple AVars, mimicking the multi-way select in the original code.
To run this program, you would need to set up a PureScript project with the necessary dependencies (purescript-aff
, purescript-avar
, etc.) and then use the PureScript compiler and runtime.
The output of this program would be similar to the original:
no message received
no message sent
no activity
This example demonstrates how to implement non-blocking operations and multi-way selects in PureScript, even though the language doesn’t have built-in channels like Go.