A process is essentially a function running concurrently to your application.

type alias Id = ProcessId

A light-weight process that runs concurrently. You can use spawn to get a bunch of different tasks running in different processes. The Gren runtime 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. So even though JS runs within a single OS-level thread, Gren can still run things concurrently.

spawn : Task x a -> Task y Id

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!

sleep : Float -> Task x {}

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.

kill : Id -> Task x {}

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.

Future Plans

Right now, this library is pretty sparse. For example, there is no public API for processes to communicate with each other. This is a really important ability, but it is also something that is extraordinarily easy to get wrong!

I think the trend will be towards an Erlang style of concurrency, where every process has an “event queue” that anyone can send messages to. I currently think the API will be extended to be more like this:

type Id exit msg

spawn : Task exit a -> Task x (Id exit Never)

kill : Id exit msg -> Task x {}

send : Id exit msg -> msg -> Task x {}

A process Id will have two type variables to make sure all communication is valid. The exit type describes the messages that are produced if the process fails because of user code. So if processes are linked and trapping errors, they will need to handle this. The msg type just describes what kind of messages this process can be sent by strangers.

We shall see though! This is just a draft that does not cover nearly everything it needs to, so the long-term vision for concurrency in Gren will be rolling out slowly as I get more data and experience.

I ask that people bullish on compiling to node.js keep this in mind. I think we can do better than the hopelessly bad concurrency model of node.js, and I hope the Gren community will be supportive of being more ambitious, even if it takes longer. That’s kind of what Gren is all about.