nri-prelude-0.7.0.0: src/Process.hs
module Process
( Id,
spawn,
sleep,
kill,
)
where
import Basics
import qualified Control.Concurrent
import qualified Control.Concurrent.Async as Async
import Internal.Shortcut
import qualified Platform.Internal as Internal
import qualified Result
import Task (Task)
import qualified Prelude
-- | A light-weight process that runs concurrently. You can use @spawn@ to get
-- a bunch of different tasks running in different processes. The Elm Haskell
-- will interleave their progress. So if a task is taking too long, we will
-- pause it at an @andThen@ and switch over to other stuff.
--
-- __Note:__ We make a distinction between concurrency which means interleaving
-- different sequences and parallelism which means running different sequences
-- at the exact same time. For example, a time-sharing system is definitely
-- concurrent, but not necessarily parallel.
newtype Id = Id (Async.Async ())
-- | Run a task in its own light-weight process. In the following example,
-- @task1@ and @task2@ will be interleaved. If @task1@ makes a long HTTP
-- request or is just taking a long time, we can hop over to @task2@ and do
-- some work there.
--
-- > spawn task1
-- > |> Task.andThen (\_ -> spawn task2)
--
-- __Note:__ This creates a relatively restricted kind of Process because it
-- cannot receive any messages. More flexibility for user-defined processes
-- will come in a later release!
spawn :: Task x a -> Task y Id
spawn (Internal.Task f) =
Internal.Task
( \handler ->
f handler
|> Async.async
|> map (Result.Ok << Id << map (\_ -> ()))
)
-- | Block progress on the current process for the given number of
-- milliseconds. The JavaScript equivalent of this is @setTimeout@ which lets
-- you delay work until later.
sleep :: Float -> Task x ()
sleep delay = Internal.Task (\_ -> map Result.Ok (Control.Concurrent.threadDelay (Prelude.floor (delay * 1000))))
-- | Sometimes you @spawn@ a process, but later decide it would be a waste to
-- have it keep running and doing stuff. The @kill@ function will force a
-- process to bail on whatever task it is running. So if there is an HTTP
-- request in flight, it will also abort the request.
kill :: Id -> Task x ()
kill (Id async) = Internal.Task (\_ -> map Result.Ok (Async.cancel async))