Skip to content

Ref

When we write programs, it is common to need to keep track of some form of state during the execution of the program. State refers to any data that can change as the program runs. For example, in a counter application, the count value changes as the user increments or decrements it. Similarly, in a banking application, the account balance changes as deposits and withdrawals are made. State management is crucial to building interactive and dynamic applications.

In traditional imperative programming, one common way to store state is using variables. However, this approach can introduce bugs, especially when the state is shared between multiple components or functions. As the program becomes more complex, managing shared state can become challenging.

To overcome these issues, Effect introduces a powerful data type called Ref, which represents a mutable reference. With Ref, we can share state between different parts of our program without relying on mutable variables directly. Instead, Ref provides a controlled way to handle mutable state and safely update it in a concurrent environment.

Effect’s Ref data type enables communication between different fibers in your program. This capability is crucial in concurrent programming, where multiple tasks may need to access and update shared state simultaneously.

In this guide, we will explore how to use the Ref data type to manage state in your programs effectively. We will cover simple examples like counting, as well as more complex scenarios where state is shared between different parts of the program. Additionally, we will show how to use Ref in a concurrent environment, allowing multiple tasks to interact with shared state safely.

Let’s dive in and see how we can leverage Ref for effective state management in your Effect programs.

Here is a simple example using Ref to create a counter:

Example (Basic Counter with Ref)

1
import {
import Effect
Effect
,
import Ref
Ref
} from "effect"
2
3
class
class Counter
Counter
{
4
(property) Counter.inc: Effect.Effect<void, never, never>
inc
:
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

The `Effect` interface defines a value that lazily describes a workflow or job. The workflow requires some context `R`, and may fail with an error of type `E`, or succeed with a value of type `A`. `Effect` values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability. To run an `Effect` value, you need a `Runtime`, which is a type that is capable of executing `Effect` values.

Effect
<void>
5
(property) Counter.dec: Effect.Effect<void, never, never>
dec
:
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

The `Effect` interface defines a value that lazily describes a workflow or job. The workflow requires some context `R`, and may fail with an error of type `E`, or succeed with a value of type `A`. `Effect` values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability. To run an `Effect` value, you need a `Runtime`, which is a type that is capable of executing `Effect` values.

Effect
<void>
6
(property) Counter.get: Effect.Effect<number, never, never>
get
:
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

The `Effect` interface defines a value that lazily describes a workflow or job. The workflow requires some context `R`, and may fail with an error of type `E`, or succeed with a value of type `A`. `Effect` values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability. To run an `Effect` value, you need a `Runtime`, which is a type that is capable of executing `Effect` values.

Effect
<number>
7
8
constructor(private
(property) Counter.value: Ref.Ref<number>
value
:
import Ref
Ref
.
interface Ref<in out A> namespace Ref
Ref
<number>) {
9
this.
(property) Counter.inc: Effect.Effect<void, never, never>
inc
=
import Ref
Ref
.
const update: <number>(self: Ref.Ref<number>, f: (a: number) => number) => Effect.Effect<void> (+1 overload)
update
(this.
(property) Counter.value: Ref.Ref<number>
value
, (
(parameter) n: number
n
) =>
(parameter) n: number
n
+ 1)
10
this.
(property) Counter.dec: Effect.Effect<void, never, never>
dec
=
import Ref
Ref
.
const update: <number>(self: Ref.Ref<number>, f: (a: number) => number) => Effect.Effect<void> (+1 overload)
update
(this.
(property) Counter.value: Ref.Ref<number>
value
, (
(parameter) n: number
n
) =>
(parameter) n: number
n
- 1)
11
this.
(property) Counter.get: Effect.Effect<number, never, never>
get
=
import Ref
Ref
.
const get: <number>(self: Ref.Ref<number>) => Effect.Effect<number, never, never>
get
(this.
(property) Counter.value: Ref.Ref<number>
value
)
12
}
13
}
14
15
const
const make: Effect.Effect<Counter, never, never>
make
=
import Effect
Effect
.
const andThen: <Ref.Ref<number>, never, never, Counter>(self: Effect.Effect<Ref.Ref<number>, never, never>, f: (a: Ref.Ref<number>) => Counter) => Effect.Effect<Counter, never, never> (+3 overloads)

Executes a sequence of two actions, typically two `Effect`s, where the second action can depend on the result of the first action. The `that` action can take various forms: - a value - a function returning a value - a promise - a function returning a promise - an effect - a function returning an effect

andThen
(
import Ref
Ref
.
const make: <number>(value: number) => Effect.Effect<Ref.Ref<number>, never, never>
make
(0), (
(parameter) value: Ref.Ref<number>
value
) => new
constructor Counter(value: Ref.Ref<number>): Counter
Counter
(
(parameter) value: Ref.Ref<number>
value
))

Example (Using the Counter)

1
import {
import Effect
Effect
,
import Ref
Ref
} from "effect"
2
13 collapsed lines
3
class
class Counter
Counter
{
4
(property) Counter.inc: Effect.Effect<void, never, never>
inc
:
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

The `Effect` interface defines a value that lazily describes a workflow or job. The workflow requires some context `R`, and may fail with an error of type `E`, or succeed with a value of type `A`. `Effect` values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability. To run an `Effect` value, you need a `Runtime`, which is a type that is capable of executing `Effect` values.

Effect
<void>
5
(property) Counter.dec: Effect.Effect<void, never, never>
dec
:
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

The `Effect` interface defines a value that lazily describes a workflow or job. The workflow requires some context `R`, and may fail with an error of type `E`, or succeed with a value of type `A`. `Effect` values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability. To run an `Effect` value, you need a `Runtime`, which is a type that is capable of executing `Effect` values.

Effect
<void>
6
(property) Counter.get: Effect.Effect<number, never, never>
get
:
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

The `Effect` interface defines a value that lazily describes a workflow or job. The workflow requires some context `R`, and may fail with an error of type `E`, or succeed with a value of type `A`. `Effect` values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability. To run an `Effect` value, you need a `Runtime`, which is a type that is capable of executing `Effect` values.

Effect
<number>
7
8
constructor(private
(property) Counter.value: Ref.Ref<number>
value
:
import Ref
Ref
.
interface Ref<in out A> namespace Ref
Ref
<number>) {
9
this.
(property) Counter.inc: Effect.Effect<void, never, never>
inc
=
import Ref
Ref
.
const update: <number>(self: Ref.Ref<number>, f: (a: number) => number) => Effect.Effect<void> (+1 overload)
update
(this.
(property) Counter.value: Ref.Ref<number>
value
, (
(parameter) n: number
n
) =>
(parameter) n: number
n
+ 1)
10
this.
(property) Counter.dec: Effect.Effect<void, never, never>
dec
=
import Ref
Ref
.
const update: <number>(self: Ref.Ref<number>, f: (a: number) => number) => Effect.Effect<void> (+1 overload)
update
(this.
(property) Counter.value: Ref.Ref<number>
value
, (
(parameter) n: number
n
) =>
(parameter) n: number
n
- 1)
11
this.
(property) Counter.get: Effect.Effect<number, never, never>
get
=
import Ref
Ref
.
const get: <number>(self: Ref.Ref<number>) => Effect.Effect<number, never, never>
get
(this.
(property) Counter.value: Ref.Ref<number>
value
)
12
}
13
}
14
15
const
const make: Effect.Effect<Counter, never, never>
make
=
import Effect
Effect
.
const andThen: <Ref.Ref<number>, never, never, Counter>(self: Effect.Effect<Ref.Ref<number>, never, never>, f: (a: Ref.Ref<number>) => Counter) => Effect.Effect<Counter, never, never> (+3 overloads)

Executes a sequence of two actions, typically two `Effect`s, where the second action can depend on the result of the first action. The `that` action can take various forms: - a value - a function returning a value - a promise - a function returning a promise - an effect - a function returning an effect

andThen
(
import Ref
Ref
.
const make: <number>(value: number) => Effect.Effect<Ref.Ref<number>, never, never>
make
(0), (
(parameter) value: Ref.Ref<number>
value
) => new
constructor Counter(value: Ref.Ref<number>): Counter
Counter
(
(parameter) value: Ref.Ref<number>
value
))
16
17
const
const program: Effect.Effect<void, never, never>
program
=
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
18
const
const counter: Counter
counter
= yield*
const make: Effect.Effect<Counter, never, never>
make
19
yield*
const counter: Counter
counter
.
(property) Counter.inc: Effect.Effect<void, never, never>
inc
20
yield*
const counter: Counter
counter
.
(property) Counter.inc: Effect.Effect<void, never, never>
inc
21
yield*
const counter: Counter
counter
.
(property) Counter.dec: Effect.Effect<void, never, never>
dec
22
yield*
const counter: Counter
counter
.
(property) Counter.inc: Effect.Effect<void, never, never>
inc
23
const
const value: number
value
= yield*
const counter: Counter
counter
.
(property) Counter.get: Effect.Effect<number, never, never>
get
24
namespace console var console: Console

The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```

console
.
(method) Console.log(message?: any, ...optionalParams: any[]): void

Prints to `stdout` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)). ```js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout ``` See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.

log
(`This counter has a value of ${
const value: number
value
}.`)
25
})
26
27
import Effect
Effect
.
const runPromise: <void, never>(effect: Effect.Effect<void, never, never>, options?: { readonly signal?: AbortSignal; } | undefined) => Promise<void>

Executes an effect and returns a `Promise` that resolves with the result. Use `runPromise` when working with asynchronous effects and you need to integrate with code that uses Promises. If the effect fails, the returned Promise will be rejected with the error.

runPromise
(
const program: Effect.Effect<void, never, never>
program
)
28
/*
29
Output:
30
This counter has a value of 2.
31
*/

We can also use Ref in concurrent scenarios, where multiple tasks might be updating shared state at the same time.

Example (Concurrent Updates to Shared Counter)

For this example, let’s update the counter concurrently:

1
import {
import Effect
Effect
,
import Ref
Ref
} from "effect"
2
13 collapsed lines
3
class
class Counter
Counter
{
4
(property) Counter.inc: Effect.Effect<void, never, never>
inc
:
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

The `Effect` interface defines a value that lazily describes a workflow or job. The workflow requires some context `R`, and may fail with an error of type `E`, or succeed with a value of type `A`. `Effect` values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability. To run an `Effect` value, you need a `Runtime`, which is a type that is capable of executing `Effect` values.

Effect
<void>
5
(property) Counter.dec: Effect.Effect<void, never, never>
dec
:
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

The `Effect` interface defines a value that lazily describes a workflow or job. The workflow requires some context `R`, and may fail with an error of type `E`, or succeed with a value of type `A`. `Effect` values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability. To run an `Effect` value, you need a `Runtime`, which is a type that is capable of executing `Effect` values.

Effect
<void>
6
(property) Counter.get: Effect.Effect<number, never, never>
get
:
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

The `Effect` interface defines a value that lazily describes a workflow or job. The workflow requires some context `R`, and may fail with an error of type `E`, or succeed with a value of type `A`. `Effect` values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability. To run an `Effect` value, you need a `Runtime`, which is a type that is capable of executing `Effect` values.

Effect
<number>
7
8
constructor(private
(property) Counter.value: Ref.Ref<number>
value
:
import Ref
Ref
.
interface Ref<in out A> namespace Ref
Ref
<number>) {
9
this.
(property) Counter.inc: Effect.Effect<void, never, never>
inc
=
import Ref
Ref
.
const update: <number>(self: Ref.Ref<number>, f: (a: number) => number) => Effect.Effect<void> (+1 overload)
update
(this.
(property) Counter.value: Ref.Ref<number>
value
, (
(parameter) n: number
n
) =>
(parameter) n: number
n
+ 1)
10
this.
(property) Counter.dec: Effect.Effect<void, never, never>
dec
=
import Ref
Ref
.
const update: <number>(self: Ref.Ref<number>, f: (a: number) => number) => Effect.Effect<void> (+1 overload)
update
(this.
(property) Counter.value: Ref.Ref<number>
value
, (
(parameter) n: number
n
) =>
(parameter) n: number
n
- 1)
11
this.
(property) Counter.get: Effect.Effect<number, never, never>
get
=
import Ref
Ref
.
const get: <number>(self: Ref.Ref<number>) => Effect.Effect<number, never, never>
get
(this.
(property) Counter.value: Ref.Ref<number>
value
)
12
}
13
}
14
15
const
const make: Effect.Effect<Counter, never, never>
make
=
import Effect
Effect
.
const andThen: <Ref.Ref<number>, never, never, Counter>(self: Effect.Effect<Ref.Ref<number>, never, never>, f: (a: Ref.Ref<number>) => Counter) => Effect.Effect<Counter, never, never> (+3 overloads)

Executes a sequence of two actions, typically two `Effect`s, where the second action can depend on the result of the first action. The `that` action can take various forms: - a value - a function returning a value - a promise - a function returning a promise - an effect - a function returning an effect

andThen
(
import Ref
Ref
.
const make: <number>(value: number) => Effect.Effect<Ref.Ref<number>, never, never>
make
(0), (
(parameter) value: Ref.Ref<number>
value
) => new
constructor Counter(value: Ref.Ref<number>): Counter
Counter
(
(parameter) value: Ref.Ref<number>
value
))
16
17
const
const program: Effect.Effect<void, never, never>
program
=
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
18
const
const counter: Counter
counter
= yield*
const make: Effect.Effect<Counter, never, never>
make
19
20
// Helper to log the counter's value before running an effect
21
const
const logCounter: <R, E, A>(label: string, effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>
logCounter
= <
(type parameter) R in <R, E, A>(label: string, effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
R
,
(type parameter) E in <R, E, A>(label: string, effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
E
,
(type parameter) A in <R, E, A>(label: string, effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
A
>(
22
(parameter) label: string
label
: string,
23
(parameter) effect: Effect.Effect<A, E, R>
effect
:
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

The `Effect` interface defines a value that lazily describes a workflow or job. The workflow requires some context `R`, and may fail with an error of type `E`, or succeed with a value of type `A`. `Effect` values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability. To run an `Effect` value, you need a `Runtime`, which is a type that is capable of executing `Effect` values.

Effect
<
(type parameter) A in <R, E, A>(label: string, effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
A
,
(type parameter) E in <R, E, A>(label: string, effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
E
,
(type parameter) R in <R, E, A>(label: string, effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
R
>
24
) =>
25
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<A, E, R>> | YieldWrap<Effect.Effect<void, never, never>>, A>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
26
const
const value: number
value
= yield*
const counter: Counter
counter
.
(property) Counter.get: Effect.Effect<number, never, never>
get
27
yield*
import Effect
Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level, which is INFO by default. This function allows logging multiple items at once and can include detailed error information using `Cause` instances. To adjust the log level, use the `Logger.withMinimumLogLevel` function.

log
(`${
(parameter) label: string
label
} get: ${
const value: number
value
}`)
28
return yield*
(parameter) effect: Effect.Effect<A, E, R>
effect
29
})
30
31
yield*
const logCounter: <never, never, void>(label: string, effect: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>
logCounter
("task 1",
const counter: Counter
counter
.
(property) Counter.inc: Effect.Effect<void, never, never>
inc
).
(method) Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<[void, void], never, never>, Effect.Effect<[[void, void], void], never, never>, Effect.Effect<[[[void, void], void], void], never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Effect.Effect<...>, cd: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
32
import Effect
Effect
.
const zip: <void, never, never>(that: Effect.Effect<void, never, never>, options?: { readonly concurrent?: boolean | undefined; readonly batching?: boolean | "inherit" | undefined; readonly concurrentFinalizers?: boolean | undefined; } | undefined) => <A, E, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+1 overload)

The `Effect.zip` function allows you to combine two effects into a single effect. This combined effect yields a tuple containing the results of both input effects once they succeed. Note that `Effect.zip` processes effects sequentially: it first completes the effect on the left and then the effect on the right. If you want to run the effects concurrently, you can use the `concurrent` option.

zip
(
const logCounter: <never, never, void>(label: string, effect: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>
logCounter
("task 2",
const counter: Counter
counter
.
(property) Counter.inc: Effect.Effect<void, never, never>
inc
), {
(property) concurrent?: boolean | undefined
concurrent
: true }),
33
import Effect
Effect
.
const zip: <void, never, never>(that: Effect.Effect<void, never, never>, options?: { readonly concurrent?: boolean | undefined; readonly batching?: boolean | "inherit" | undefined; readonly concurrentFinalizers?: boolean | undefined; } | undefined) => <A, E, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+1 overload)

The `Effect.zip` function allows you to combine two effects into a single effect. This combined effect yields a tuple containing the results of both input effects once they succeed. Note that `Effect.zip` processes effects sequentially: it first completes the effect on the left and then the effect on the right. If you want to run the effects concurrently, you can use the `concurrent` option.

zip
(
const logCounter: <never, never, void>(label: string, effect: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>
logCounter
("task 3",
const counter: Counter
counter
.
(property) Counter.dec: Effect.Effect<void, never, never>
dec
), {
(property) concurrent?: boolean | undefined
concurrent
: true }),
34
import Effect
Effect
.
const zip: <void, never, never>(that: Effect.Effect<void, never, never>, options?: { readonly concurrent?: boolean | undefined; readonly batching?: boolean | "inherit" | undefined; readonly concurrentFinalizers?: boolean | undefined; } | undefined) => <A, E, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+1 overload)

The `Effect.zip` function allows you to combine two effects into a single effect. This combined effect yields a tuple containing the results of both input effects once they succeed. Note that `Effect.zip` processes effects sequentially: it first completes the effect on the left and then the effect on the right. If you want to run the effects concurrently, you can use the `concurrent` option.

zip
(
const logCounter: <never, never, void>(label: string, effect: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>
logCounter
("task 4",
const counter: Counter
counter
.
(property) Counter.inc: Effect.Effect<void, never, never>
inc
), {
(property) concurrent?: boolean | undefined
concurrent
: true })
35
)
36
const
const value: number
value
= yield*
const counter: Counter
counter
.
(property) Counter.get: Effect.Effect<number, never, never>
get
37
yield*
import Effect
Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level, which is INFO by default. This function allows logging multiple items at once and can include detailed error information using `Cause` instances. To adjust the log level, use the `Logger.withMinimumLogLevel` function.

log
(`This counter has a value of ${
const value: number
value
}.`)
38
})
39
40
import Effect
Effect
.
const runPromise: <void, never>(effect: Effect.Effect<void, never, never>, options?: { readonly signal?: AbortSignal; } | undefined) => Promise<void>

Executes an effect and returns a `Promise` that resolves with the result. Use `runPromise` when working with asynchronous effects and you need to integrate with code that uses Promises. If the effect fails, the returned Promise will be rejected with the error.

runPromise
(
const program: Effect.Effect<void, never, never>
program
)
41
/*
42
Output:
43
timestamp=... fiber=#3 message="task 4 get: 0"
44
timestamp=... fiber=#6 message="task 3 get: 1"
45
timestamp=... fiber=#8 message="task 1 get: 0"
46
timestamp=... fiber=#9 message="task 2 get: 1"
47
timestamp=... fiber=#0 message="This counter has a value of 2."
48
*/

You can pass a Ref as a service to share state across different parts of your program.

Example (Using Ref as a Service)

1
import {
import Effect
Effect
,
import Context
Context
,
import Ref
Ref
} from "effect"
2
3
// Create a Tag for our state
4
class
class MyState
MyState
extends
import Context
Context
.
const Tag: <"MyState">(id: "MyState") => <Self, Shape>() => Context.TagClass<Self, "MyState", Shape> namespace Tag
Tag
("MyState")<
5
class MyState
MyState
,
6
import Ref
Ref
.
interface Ref<in out A> namespace Ref
Ref
<number>
7
>() {}
8
9
// Subprogram 1: Increment the state value twice
10
const
const subprogram1: Effect.Effect<void, never, MyState>
subprogram1
=
import Effect
Effect
.
const gen: <YieldWrap<Context.Tag<MyState, Ref.Ref<number>>> | YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
11
const
const state: Ref.Ref<number>
state
= yield*
class MyState
MyState
12
yield*
import Ref
Ref
.
const update: <number>(self: Ref.Ref<number>, f: (a: number) => number) => Effect.Effect<void> (+1 overload)
update
(
const state: Ref.Ref<number>
state
, (
(parameter) n: number
n
) =>
(parameter) n: number
n
+ 1)
13
yield*
import Ref
Ref
.
const update: <number>(self: Ref.Ref<number>, f: (a: number) => number) => Effect.Effect<void> (+1 overload)
update
(
const state: Ref.Ref<number>
state
, (
(parameter) n: number
n
) =>
(parameter) n: number
n
+ 1)
14
})
15
16
// Subprogram 2: Decrement the state value and then increment it
17
const
const subprogram2: Effect.Effect<void, never, MyState>
subprogram2
=
import Effect
Effect
.
const gen: <YieldWrap<Context.Tag<MyState, Ref.Ref<number>>> | YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
18
const
const state: Ref.Ref<number>
state
= yield*
class MyState
MyState
19
yield*
import Ref
Ref
.
const update: <number>(self: Ref.Ref<number>, f: (a: number) => number) => Effect.Effect<void> (+1 overload)
update
(
const state: Ref.Ref<number>
state
, (
(parameter) n: number
n
) =>
(parameter) n: number
n
- 1)
20
yield*
import Ref
Ref
.
const update: <number>(self: Ref.Ref<number>, f: (a: number) => number) => Effect.Effect<void> (+1 overload)
update
(
const state: Ref.Ref<number>
state
, (
(parameter) n: number
n
) =>
(parameter) n: number
n
+ 1)
21
})
22
23
// Subprogram 3: Read and log the current value of the state
24
const
const subprogram3: Effect.Effect<void, never, MyState>
subprogram3
=
import Effect
Effect
.
const gen: <YieldWrap<Context.Tag<MyState, Ref.Ref<number>>> | YieldWrap<Effect.Effect<number, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
25
const
const state: Ref.Ref<number>
state
= yield*
class MyState
MyState
26
const
const value: number
value
= yield*
import Ref
Ref
.
const get: <number>(self: Ref.Ref<number>) => Effect.Effect<number, never, never>
get
(
const state: Ref.Ref<number>
state
)
27
namespace console var console: Console

The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```

console
.
(method) Console.log(message?: any, ...optionalParams: any[]): void

Prints to `stdout` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)). ```js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout ``` See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.

log
(`MyState has a value of ${
const value: number
value
}.`)
28
})
29
30
// Compose subprograms 1, 2, and 3 to create the main program
31
const
const program: Effect.Effect<void, never, MyState>
program
=
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, MyState>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, MyState>>, void, never>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
32
yield*
const subprogram1: Effect.Effect<void, never, MyState>
subprogram1
33
yield*
const subprogram2: Effect.Effect<void, never, MyState>
subprogram2
34
yield*
const subprogram3: Effect.Effect<void, never, MyState>
subprogram3
35
})
36
37
// Create a Ref instance with an initial value of 0
38
const
const initialState: Effect.Effect<Ref.Ref<number>, never, never>
initialState
=
import Ref
Ref
.
const make: <number>(value: number) => Effect.Effect<Ref.Ref<number>, never, never>
make
(0)
39
40
// Provide the Ref as a service
41
const
const runnable: Effect.Effect<void, never, never>
runnable
=
const program: Effect.Effect<void, never, MyState>
program
.
(method) Pipeable.pipe<Effect.Effect<void, never, MyState>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<void, never, MyState>) => Effect.Effect<void, never, never>): Effect.Effect<...> (+21 overloads)
pipe
(
42
import Effect
Effect
.
const provideServiceEffect: <typeof MyState, never, never>(tag: typeof MyState, effect: Effect.Effect<Ref.Ref<number>, never, never>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<...> (+1 overload)

Provides the effect with the single service it requires. If the effect requires more than one service use `provide` instead.

provideServiceEffect
(
class MyState
MyState
,
const initialState: Effect.Effect<Ref.Ref<number>, never, never>
initialState
)
43
)
44
45
// Run the program and observe the output
46
import Effect
Effect
.
const runPromise: <void, never>(effect: Effect.Effect<void, never, never>, options?: { readonly signal?: AbortSignal; } | undefined) => Promise<void>

Executes an effect and returns a `Promise` that resolves with the result. Use `runPromise` when working with asynchronous effects and you need to integrate with code that uses Promises. If the effect fails, the returned Promise will be rejected with the error.

runPromise
(
const runnable: Effect.Effect<void, never, never>
runnable
)
47
/*
48
Output:
49
MyState has a value of 2.
50
*/

Note that we use Effect.provideServiceEffect instead of Effect.provideService to provide an actual implementation of the MyState service because all the operations on the Ref data type are effectful, including the creation Ref.make(0).

You can use Ref to manage shared state between multiple fibers in a concurrent environment.

Example (Managing Shared State Across Fibers)

Let’s look at an example where we continuously read names from user input until the user enters "q" to exit.

First, let’s introduce a readLine utility to read user input (ensure you have @types/node installed):

1
import {
import Effect
Effect
} from "effect"
2
import * as
(alias) module "node:readline" import NodeReadLine
NodeReadLine
from "node:readline"
3
4
// Utility to read user input
5
const
const readLine: (message: string) => Effect.Effect<string>
readLine
= (
(parameter) message: string
message
: string):
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

The `Effect` interface defines a value that lazily describes a workflow or job. The workflow requires some context `R`, and may fail with an error of type `E`, or succeed with a value of type `A`. `Effect` values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability. To run an `Effect` value, you need a `Runtime`, which is a type that is capable of executing `Effect` values.

Effect
<string> =>
6
import Effect
Effect
.
const promise: <string>(evaluate: (signal: AbortSignal) => PromiseLike<string>) => Effect.Effect<string, never, never>

Creates an `Effect` that represents an asynchronous computation guaranteed to succeed. The provided function (`thunk`) returns a `Promise` that should never reject. If the `Promise` does reject, the rejection is treated as a defect. An optional `AbortSignal` can be provided to allow for interruption of the wrapped `Promise` API.

promise
(
7
() =>
8
new
var Promise: PromiseConstructor new <string>(executor: (resolve: (value: string | PromiseLike<string>) => void, reject: (reason?: any) => void) => void) => Promise<string>

Creates a new Promise.

Promise
((
(parameter) resolve: (value: string | PromiseLike<string>) => void
resolve
) => {
9
const
const rl: NodeReadLine.Interface
rl
=
(alias) module "node:readline" import NodeReadLine
NodeReadLine
.
function createInterface(options: NodeReadLine.ReadLineOptions): NodeReadLine.Interface (+1 overload)

The `readline.createInterface()` method creates a new `readline.Interface` instance. ```js import readline from 'node:readline'; const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); ``` Once the `readline.Interface` instance is created, the most common case is to listen for the `'line'` event: ```js rl.on('line', (line) => { console.log(`Received: ${line}`); }); ``` If `terminal` is `true` for this instance then the `output` stream will get the best compatibility if it defines an `output.columns` property and emits a `'resize'` event on the `output` if or when the columns ever change (`process.stdout` does this automatically when it is a TTY). When creating a `readline.Interface` using `stdin` as input, the program will not terminate until it receives an [EOF character](https://en.wikipedia.org/wiki/End-of-file#EOF_character). To exit without waiting for user input, call `process.stdin.unref()`.

createInterface
({
10
(property) ReadLineOptions.input: NodeJS.ReadableStream
input
:
var process: NodeJS.Process
process
.
(property) NodeJS.Process.stdin: NodeJS.ReadStream & { fd: 0; }

The `process.stdin` property returns a stream connected to`stdin` (fd `0`). It is a `net.Socket` (which is a `Duplex` stream) unless fd `0` refers to a file, in which case it is a `Readable` stream. For details of how to read from `stdin` see `readable.read()`. As a `Duplex` stream, `process.stdin` can also be used in "old" mode that is compatible with scripts written for Node.js prior to v0.10\. For more information see `Stream compatibility`. In "old" streams mode the `stdin` stream is paused by default, so one must call `process.stdin.resume()` to read from it. Note also that calling `process.stdin.resume()` itself would switch stream to "old" mode.

stdin
,
11
(property) ReadLineOptions.output?: NodeJS.WritableStream | undefined
output
:
var process: NodeJS.Process
process
.
(property) NodeJS.Process.stdout: NodeJS.WriteStream & { fd: 1; }

The `process.stdout` property returns a stream connected to`stdout` (fd `1`). It is a `net.Socket` (which is a `Duplex` stream) unless fd `1` refers to a file, in which case it is a `Writable` stream. For example, to copy `process.stdin` to `process.stdout`: ```js import { stdin, stdout } from 'node:process'; stdin.pipe(stdout); ``` `process.stdout` differs from other Node.js streams in important ways. See `note on process I/O` for more information.

stdout
12
})
13
const rl: NodeReadLine.Interface
rl
.
(method) Interface.question(query: string, callback: (answer: string) => void): void (+1 overload)

The `rl.question()` method displays the `query` by writing it to the `output`, waits for user input to be provided on `input`, then invokes the `callback` function passing the provided input as the first argument. When called, `rl.question()` will resume the `input` stream if it has been paused. If the `Interface` was created with `output` set to `null` or `undefined` the `query` is not written. The `callback` function passed to `rl.question()` does not follow the typical pattern of accepting an `Error` object or `null` as the first argument. The `callback` is called with the provided answer as the only argument. An error will be thrown if calling `rl.question()` after `rl.close()`. Example usage: ```js rl.question('What is your favorite food? ', (answer) => { console.log(`Oh, so your favorite food is ${answer}`); }); ``` Using an `AbortController` to cancel a question. ```js const ac = new AbortController(); const signal = ac.signal; rl.question('What is your favorite food? ', { signal }, (answer) => { console.log(`Oh, so your favorite food is ${answer}`); }); signal.addEventListener('abort', () => { console.log('The food question timed out'); }, { once: true }); setTimeout(() => ac.abort(), 10000); ```

question
(
(parameter) message: string
message
, (
(parameter) answer: string
answer
) => {
14
const rl: NodeReadLine.Interface
rl
.
(method) Interface.close(): void

The `rl.close()` method closes the `Interface` instance and relinquishes control over the `input` and `output` streams. When called, the `'close'` event will be emitted. Calling `rl.close()` does not immediately stop other events (including `'line'`) from being emitted by the `Interface` instance.

close
()
15
(parameter) resolve: (value: string | PromiseLike<string>) => void
resolve
(
(parameter) answer: string
answer
)
16
})
17
})
18
)

Next, we implement the main program to collect names:

1
import {
import Effect
Effect
,
import Chunk
Chunk
,
import Ref
Ref
} from "effect"
2
import * as
(alias) module "node:readline" import NodeReadLine
NodeReadLine
from "node:readline"
3
4
// Utility to read user input
14 collapsed lines
5
const
const readLine: (message: string) => Effect.Effect<string>
readLine
= (
(parameter) message: string
message
: string):
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

The `Effect` interface defines a value that lazily describes a workflow or job. The workflow requires some context `R`, and may fail with an error of type `E`, or succeed with a value of type `A`. `Effect` values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability. To run an `Effect` value, you need a `Runtime`, which is a type that is capable of executing `Effect` values.

Effect
<string> =>
6
import Effect
Effect
.
const promise: <string>(evaluate: (signal: AbortSignal) => PromiseLike<string>) => Effect.Effect<string, never, never>

Creates an `Effect` that represents an asynchronous computation guaranteed to succeed. The provided function (`thunk`) returns a `Promise` that should never reject. If the `Promise` does reject, the rejection is treated as a defect. An optional `AbortSignal` can be provided to allow for interruption of the wrapped `Promise` API.

promise
(
7
() =>
8
new
var Promise: PromiseConstructor new <string>(executor: (resolve: (value: string | PromiseLike<string>) => void, reject: (reason?: any) => void) => void) => Promise<string>

Creates a new Promise.

Promise
((
(parameter) resolve: (value: string | PromiseLike<string>) => void
resolve
) => {
9
const
const rl: NodeReadLine.Interface
rl
=
(alias) module "node:readline" import NodeReadLine
NodeReadLine
.
function createInterface(options: NodeReadLine.ReadLineOptions): NodeReadLine.Interface (+1 overload)

The `readline.createInterface()` method creates a new `readline.Interface` instance. ```js import readline from 'node:readline'; const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); ``` Once the `readline.Interface` instance is created, the most common case is to listen for the `'line'` event: ```js rl.on('line', (line) => { console.log(`Received: ${line}`); }); ``` If `terminal` is `true` for this instance then the `output` stream will get the best compatibility if it defines an `output.columns` property and emits a `'resize'` event on the `output` if or when the columns ever change (`process.stdout` does this automatically when it is a TTY). When creating a `readline.Interface` using `stdin` as input, the program will not terminate until it receives an [EOF character](https://en.wikipedia.org/wiki/End-of-file#EOF_character). To exit without waiting for user input, call `process.stdin.unref()`.

createInterface
({
10
(property) ReadLineOptions.input: NodeJS.ReadableStream
input
:
var process: NodeJS.Process
process
.
(property) NodeJS.Process.stdin: NodeJS.ReadStream & { fd: 0; }

The `process.stdin` property returns a stream connected to`stdin` (fd `0`). It is a `net.Socket` (which is a `Duplex` stream) unless fd `0` refers to a file, in which case it is a `Readable` stream. For details of how to read from `stdin` see `readable.read()`. As a `Duplex` stream, `process.stdin` can also be used in "old" mode that is compatible with scripts written for Node.js prior to v0.10\. For more information see `Stream compatibility`. In "old" streams mode the `stdin` stream is paused by default, so one must call `process.stdin.resume()` to read from it. Note also that calling `process.stdin.resume()` itself would switch stream to "old" mode.

stdin
,
11
(property) ReadLineOptions.output?: NodeJS.WritableStream | undefined
output
:
var process: NodeJS.Process
process
.
(property) NodeJS.Process.stdout: NodeJS.WriteStream & { fd: 1; }

The `process.stdout` property returns a stream connected to`stdout` (fd `1`). It is a `net.Socket` (which is a `Duplex` stream) unless fd `1` refers to a file, in which case it is a `Writable` stream. For example, to copy `process.stdin` to `process.stdout`: ```js import { stdin, stdout } from 'node:process'; stdin.pipe(stdout); ``` `process.stdout` differs from other Node.js streams in important ways. See `note on process I/O` for more information.

stdout
12
})
13
const rl: NodeReadLine.Interface
rl
.
(method) Interface.question(query: string, callback: (answer: string) => void): void (+1 overload)

The `rl.question()` method displays the `query` by writing it to the `output`, waits for user input to be provided on `input`, then invokes the `callback` function passing the provided input as the first argument. When called, `rl.question()` will resume the `input` stream if it has been paused. If the `Interface` was created with `output` set to `null` or `undefined` the `query` is not written. The `callback` function passed to `rl.question()` does not follow the typical pattern of accepting an `Error` object or `null` as the first argument. The `callback` is called with the provided answer as the only argument. An error will be thrown if calling `rl.question()` after `rl.close()`. Example usage: ```js rl.question('What is your favorite food? ', (answer) => { console.log(`Oh, so your favorite food is ${answer}`); }); ``` Using an `AbortController` to cancel a question. ```js const ac = new AbortController(); const signal = ac.signal; rl.question('What is your favorite food? ', { signal }, (answer) => { console.log(`Oh, so your favorite food is ${answer}`); }); signal.addEventListener('abort', () => { console.log('The food question timed out'); }, { once: true }); setTimeout(() => ac.abort(), 10000); ```

question
(
(parameter) message: string
message
, (
(parameter) answer: string
answer
) => {
14
const rl: NodeReadLine.Interface
rl
.
(method) Interface.close(): void

The `rl.close()` method closes the `Interface` instance and relinquishes control over the `input` and `output` streams. When called, the `'close'` event will be emitted. Calling `rl.close()` does not immediately stop other events (including `'line'`) from being emitted by the `Interface` instance.

close
()
15
(parameter) resolve: (value: string | PromiseLike<string>) => void
resolve
(
(parameter) answer: string
answer
)
16
})
17
})
18
)
19
20
const
const getNames: Effect.Effect<Chunk.Chunk<string>, never, never>
getNames
=
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, Chunk.Chunk<string>>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, Chunk.Chunk<...>, never>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
21
const
const ref: Ref.Ref<Chunk.Chunk<string>>
ref
= yield*
import Ref
Ref
.
const make: <Chunk.Chunk<string>>(value: Chunk.Chunk<string>) => Effect.Effect<Ref.Ref<Chunk.Chunk<string>>, never, never>
make
(
import Chunk
Chunk
.
const empty: <string>() => Chunk.Chunk<string>
empty
<string>())
22
while (true) {
23
const
const name: string
name
= yield*
const readLine: (message: string) => Effect.Effect<string>
readLine
("Please enter a name or `q` to exit: ")
24
if (
const name: string
name
=== "q") {
25
break
26
}
27
yield*
import Ref
Ref
.
const update: <Chunk.Chunk<string>>(self: Ref.Ref<Chunk.Chunk<string>>, f: (a: Chunk.Chunk<string>) => Chunk.Chunk<string>) => Effect.Effect<void> (+1 overload)
update
(
const ref: Ref.Ref<Chunk.Chunk<string>>
ref
, (
(parameter) state: Chunk.Chunk<string>
state
) =>
import Chunk
Chunk
.
const append: <string, string>(self: Chunk.Chunk<string>, a: string) => Chunk.NonEmptyChunk<string> (+1 overload)

Appends the specified element to the end of the `Chunk`.

append
(
(parameter) state: Chunk.Chunk<string>
state
,
const name: string
name
))
28
}
29
return yield*
import Ref
Ref
.
const get: <Chunk.Chunk<string>>(self: Ref.Ref<Chunk.Chunk<string>>) => Effect.Effect<Chunk.Chunk<string>, never, never>
get
(
const ref: Ref.Ref<Chunk.Chunk<string>>
ref
)
30
})
31
32
import Effect
Effect
.
const runPromise: <Chunk.Chunk<string>, never>(effect: Effect.Effect<Chunk.Chunk<string>, never, never>, options?: { readonly signal?: AbortSignal; } | undefined) => Promise<...>

Executes an effect and returns a `Promise` that resolves with the result. Use `runPromise` when working with asynchronous effects and you need to integrate with code that uses Promises. If the effect fails, the returned Promise will be rejected with the error.

runPromise
(
const getNames: Effect.Effect<Chunk.Chunk<string>, never, never>
getNames
).
(method) Promise<Chunk<string>>.then<void, never>(onfulfilled?: ((value: Chunk.Chunk<string>) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>

Attaches callbacks for the resolution and/or rejection of the Promise.

then
(
namespace console var console: Console

The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```

console
.
(method) Console.log(message?: any, ...optionalParams: any[]): void

Prints to `stdout` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)). ```js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout ``` See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.

log
)
33
/*
34
Output:
35
Please enter a name or `q` to exit: Alice
36
Please enter a name or `q` to exit: Bob
37
Please enter a name or `q` to exit: q
38
{
39
_id: "Chunk",
40
values: [ "Alice", "Bob" ]
41
}
42
*/

Now that we have learned how to use the Ref data type, we can use it to manage the state concurrently.

For example, assume while we are reading from the console, we have another fiber that is trying to update the state from a different source.

Here, one fiber reads names from user input, while another fiber concurrently adds preset names at regular intervals:

1
import {
import Effect
Effect
,
import Chunk
Chunk
,
import Ref
Ref
,
import Fiber
Fiber
} from "effect"
2
import * as
(alias) module "node:readline" import NodeReadLine
NodeReadLine
from "node:readline"
3
4
// Utility to read user input
14 collapsed lines
5
const
const readLine: (message: string) => Effect.Effect<string>
readLine
= (
(parameter) message: string
message
: string):
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

The `Effect` interface defines a value that lazily describes a workflow or job. The workflow requires some context `R`, and may fail with an error of type `E`, or succeed with a value of type `A`. `Effect` values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability. To run an `Effect` value, you need a `Runtime`, which is a type that is capable of executing `Effect` values.

Effect
<string> =>
6
import Effect
Effect
.
const promise: <string>(evaluate: (signal: AbortSignal) => PromiseLike<string>) => Effect.Effect<string, never, never>

Creates an `Effect` that represents an asynchronous computation guaranteed to succeed. The provided function (`thunk`) returns a `Promise` that should never reject. If the `Promise` does reject, the rejection is treated as a defect. An optional `AbortSignal` can be provided to allow for interruption of the wrapped `Promise` API.

promise
(
7
() =>
8
new
var Promise: PromiseConstructor new <string>(executor: (resolve: (value: string | PromiseLike<string>) => void, reject: (reason?: any) => void) => void) => Promise<string>

Creates a new Promise.

Promise
((
(parameter) resolve: (value: string | PromiseLike<string>) => void
resolve
) => {
9
const
const rl: NodeReadLine.Interface
rl
=
(alias) module "node:readline" import NodeReadLine
NodeReadLine
.
function createInterface(options: NodeReadLine.ReadLineOptions): NodeReadLine.Interface (+1 overload)

The `readline.createInterface()` method creates a new `readline.Interface` instance. ```js import readline from 'node:readline'; const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); ``` Once the `readline.Interface` instance is created, the most common case is to listen for the `'line'` event: ```js rl.on('line', (line) => { console.log(`Received: ${line}`); }); ``` If `terminal` is `true` for this instance then the `output` stream will get the best compatibility if it defines an `output.columns` property and emits a `'resize'` event on the `output` if or when the columns ever change (`process.stdout` does this automatically when it is a TTY). When creating a `readline.Interface` using `stdin` as input, the program will not terminate until it receives an [EOF character](https://en.wikipedia.org/wiki/End-of-file#EOF_character). To exit without waiting for user input, call `process.stdin.unref()`.

createInterface
({
10
(property) ReadLineOptions.input: NodeJS.ReadableStream
input
:
var process: NodeJS.Process
process
.
(property) NodeJS.Process.stdin: NodeJS.ReadStream & { fd: 0; }

The `process.stdin` property returns a stream connected to`stdin` (fd `0`). It is a `net.Socket` (which is a `Duplex` stream) unless fd `0` refers to a file, in which case it is a `Readable` stream. For details of how to read from `stdin` see `readable.read()`. As a `Duplex` stream, `process.stdin` can also be used in "old" mode that is compatible with scripts written for Node.js prior to v0.10\. For more information see `Stream compatibility`. In "old" streams mode the `stdin` stream is paused by default, so one must call `process.stdin.resume()` to read from it. Note also that calling `process.stdin.resume()` itself would switch stream to "old" mode.

stdin
,
11
(property) ReadLineOptions.output?: NodeJS.WritableStream | undefined
output
:
var process: NodeJS.Process
process
.
(property) NodeJS.Process.stdout: NodeJS.WriteStream & { fd: 1; }

The `process.stdout` property returns a stream connected to`stdout` (fd `1`). It is a `net.Socket` (which is a `Duplex` stream) unless fd `1` refers to a file, in which case it is a `Writable` stream. For example, to copy `process.stdin` to `process.stdout`: ```js import { stdin, stdout } from 'node:process'; stdin.pipe(stdout); ``` `process.stdout` differs from other Node.js streams in important ways. See `note on process I/O` for more information.

stdout
12
})
13
const rl: NodeReadLine.Interface
rl
.
(method) Interface.question(query: string, callback: (answer: string) => void): void (+1 overload)

The `rl.question()` method displays the `query` by writing it to the `output`, waits for user input to be provided on `input`, then invokes the `callback` function passing the provided input as the first argument. When called, `rl.question()` will resume the `input` stream if it has been paused. If the `Interface` was created with `output` set to `null` or `undefined` the `query` is not written. The `callback` function passed to `rl.question()` does not follow the typical pattern of accepting an `Error` object or `null` as the first argument. The `callback` is called with the provided answer as the only argument. An error will be thrown if calling `rl.question()` after `rl.close()`. Example usage: ```js rl.question('What is your favorite food? ', (answer) => { console.log(`Oh, so your favorite food is ${answer}`); }); ``` Using an `AbortController` to cancel a question. ```js const ac = new AbortController(); const signal = ac.signal; rl.question('What is your favorite food? ', { signal }, (answer) => { console.log(`Oh, so your favorite food is ${answer}`); }); signal.addEventListener('abort', () => { console.log('The food question timed out'); }, { once: true }); setTimeout(() => ac.abort(), 10000); ```

question
(
(parameter) message: string
message
, (
(parameter) answer: string
answer
) => {
14
const rl: NodeReadLine.Interface
rl
.
(method) Interface.close(): void

The `rl.close()` method closes the `Interface` instance and relinquishes control over the `input` and `output` streams. When called, the `'close'` event will be emitted. Calling `rl.close()` does not immediately stop other events (including `'line'`) from being emitted by the `Interface` instance.

close
()
15
(parameter) resolve: (value: string | PromiseLike<string>) => void
resolve
(
(parameter) answer: string
answer
)
16
})
17
})
18
)
19
20
const
const getNames: Effect.Effect<Chunk.Chunk<string>, never, never>
getNames
=
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, Chunk.Chunk<string>>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, Chunk.Chunk<...>, never>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
21
const
const ref: Ref.Ref<Chunk.Chunk<string>>
ref
= yield*
import Ref
Ref
.
const make: <Chunk.Chunk<string>>(value: Chunk.Chunk<string>) => Effect.Effect<Ref.Ref<Chunk.Chunk<string>>, never, never>
make
(
import Chunk
Chunk
.
const empty: <string>() => Chunk.Chunk<string>
empty
<string>())
22
23
// Fiber 1: Reading names from user input
24
const
const fiber1: Fiber.RuntimeFiber<void, never>
fiber1
= yield*
import Effect
Effect
.
const fork: <void, never, never>(self: Effect.Effect<void, never, never>) => Effect.Effect<Fiber.RuntimeFiber<void, never>, never, never>

Returns an effect that forks this effect into its own separate fiber, returning the fiber immediately, without waiting for it to begin executing the effect. You can use the `fork` method whenever you want to execute an effect in a new fiber, concurrently and without "blocking" the fiber executing other effects. Using fibers can be tricky, so instead of using this method directly, consider other higher-level methods, such as `raceWith`, `zipPar`, and so forth. The fiber returned by this method has methods to interrupt the fiber and to wait for it to finish executing the effect. See `Fiber` for more information. Whenever you use this method to launch a new fiber, the new fiber is attached to the parent fiber's scope. This means when the parent fiber terminates, the child fiber will be terminated as well, ensuring that no fibers leak. This behavior is called "auto supervision", and if this behavior is not desired, you may use the `forkDaemon` or `forkIn` methods.

fork
(
25
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
26
while (true) {
27
const
const name: string
name
= yield*
const readLine: (message: string) => Effect.Effect<string>
readLine
(
28
"Please enter a name or `q` to exit: "
29
)
30
if (
const name: string
name
=== "q") {
31
break
32
}
33
yield*
import Ref
Ref
.
const update: <Chunk.Chunk<string>>(self: Ref.Ref<Chunk.Chunk<string>>, f: (a: Chunk.Chunk<string>) => Chunk.Chunk<string>) => Effect.Effect<void> (+1 overload)
update
(
const ref: Ref.Ref<Chunk.Chunk<string>>
ref
, (
(parameter) state: Chunk.Chunk<string>
state
) =>
import Chunk
Chunk
.
const append: <string, string>(self: Chunk.Chunk<string>, a: string) => Chunk.NonEmptyChunk<string> (+1 overload)

Appends the specified element to the end of the `Chunk`.

append
(
(parameter) state: Chunk.Chunk<string>
state
,
const name: string
name
))
34
}
35
})
36
)
37
38
// Fiber 2: Updating the state with predefined names
39
const
const fiber2: Fiber.RuntimeFiber<void, never>
fiber2
= yield*
import Effect
Effect
.
const fork: <void, never, never>(self: Effect.Effect<void, never, never>) => Effect.Effect<Fiber.RuntimeFiber<void, never>, never, never>

Returns an effect that forks this effect into its own separate fiber, returning the fiber immediately, without waiting for it to begin executing the effect. You can use the `fork` method whenever you want to execute an effect in a new fiber, concurrently and without "blocking" the fiber executing other effects. Using fibers can be tricky, so instead of using this method directly, consider other higher-level methods, such as `raceWith`, `zipPar`, and so forth. The fiber returned by this method has methods to interrupt the fiber and to wait for it to finish executing the effect. See `Fiber` for more information. Whenever you use this method to launch a new fiber, the new fiber is attached to the parent fiber's scope. This means when the parent fiber terminates, the child fiber will be terminated as well, ensuring that no fibers leak. This behavior is called "auto supervision", and if this behavior is not desired, you may use the `forkDaemon` or `forkIn` methods.

fork
(
40
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
41
for (const
const name: string
name
of ["John", "Jane", "Joe", "Tom"]) {
42
yield*
import Ref
Ref
.
const update: <Chunk.Chunk<string>>(self: Ref.Ref<Chunk.Chunk<string>>, f: (a: Chunk.Chunk<string>) => Chunk.Chunk<string>) => Effect.Effect<void> (+1 overload)
update
(
const ref: Ref.Ref<Chunk.Chunk<string>>
ref
, (
(parameter) state: Chunk.Chunk<string>
state
) =>
import Chunk
Chunk
.
const append: <string, string>(self: Chunk.Chunk<string>, a: string) => Chunk.NonEmptyChunk<string> (+1 overload)

Appends the specified element to the end of the `Chunk`.

append
(
(parameter) state: Chunk.Chunk<string>
state
,
const name: string
name
))
43
yield*
import Effect
Effect
.
const sleep: (duration: DurationInput) => Effect.Effect<void>

Returns an effect that suspends for the specified duration. This method is asynchronous, and does not actually block the fiber executing the effect.

sleep
("1 second")
44
}
45
})
46
)
47
yield*
import Fiber
Fiber
.
const join: <void, never>(self: Fiber.Fiber<void, never>) => Effect.Effect<void, never, never>

Joins the fiber, which suspends the joining fiber until the result of the fiber has been determined. Attempting to join a fiber that has erred will result in a catchable error. Joining an interrupted fiber will result in an "inner interruption" of this fiber, unlike interruption triggered by another fiber, "inner interruption" can be caught and recovered.

join
(
const fiber1: Fiber.RuntimeFiber<void, never>
fiber1
)
48
yield*
import Fiber
Fiber
.
const join: <void, never>(self: Fiber.Fiber<void, never>) => Effect.Effect<void, never, never>

Joins the fiber, which suspends the joining fiber until the result of the fiber has been determined. Attempting to join a fiber that has erred will result in a catchable error. Joining an interrupted fiber will result in an "inner interruption" of this fiber, unlike interruption triggered by another fiber, "inner interruption" can be caught and recovered.

join
(
const fiber2: Fiber.RuntimeFiber<void, never>
fiber2
)
49
return yield*
import Ref
Ref
.
const get: <Chunk.Chunk<string>>(self: Ref.Ref<Chunk.Chunk<string>>) => Effect.Effect<Chunk.Chunk<string>, never, never>
get
(
const ref: Ref.Ref<Chunk.Chunk<string>>
ref
)
50
})
51
52
import Effect
Effect
.
const runPromise: <Chunk.Chunk<string>, never>(effect: Effect.Effect<Chunk.Chunk<string>, never, never>, options?: { readonly signal?: AbortSignal; } | undefined) => Promise<...>

Executes an effect and returns a `Promise` that resolves with the result. Use `runPromise` when working with asynchronous effects and you need to integrate with code that uses Promises. If the effect fails, the returned Promise will be rejected with the error.

runPromise
(
const getNames: Effect.Effect<Chunk.Chunk<string>, never, never>
getNames
).
(method) Promise<Chunk<string>>.then<void, never>(onfulfilled?: ((value: Chunk.Chunk<string>) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>

Attaches callbacks for the resolution and/or rejection of the Promise.

then
(
namespace console var console: Console

The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```

console
.
(method) Console.log(message?: any, ...optionalParams: any[]): void

Prints to `stdout` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)). ```js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout ``` See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.

log
)
53
/*
54
Output:
55
Please enter a name or `q` to exit: Alice
56
Please enter a name or `q` to exit: Bob
57
Please enter a name or `q` to exit: q
58
{
59
_id: "Chunk",
60
values: [ ... ]
61
}
62
*/