You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Programming with side-effects is hard: To reason about a unit in your code, like a function, you need to know what the other units in the program are doing to the program state, and understand how that affects what you're trying to achieve.
7
7
8
-
Programming without side-effects is _less_ hard: To reason about a unit in you code, like a function, you can focus on what _that_ function is doing, since the units it interacts with don't affect the state of the program in any way.
8
+
Programming without side-effects is _less_ hard: To reason about a unit in your code, like a function, you can focus on what _that_ function is doing, since the units it interacts with don't affect the state of the program in any way.
9
9
10
10
But of course side-effects can't be avoided, since what we ultimately care about in programming are the side effects, such as printing to the console or writing to a database.
11
11
@@ -15,10 +15,21 @@ As a result, "business logic" code never performs side-effects, which makes it e
15
15
16
16
# Quickstart
17
17
18
+
## Install
19
+
20
+
21
+
```console
22
+
> pip install stateless
23
+
```
24
+
25
+
26
+
## Usage
27
+
28
+
18
29
```python
19
30
from typing import Any, Never
20
31
21
-
from stateless import Effect, Need, need, throws, catch, run
32
+
from stateless import Effect, Need, need, throws, catch, run, supply
type Effect[A: Ability, E: Exception, R] = Generator[A | E, Any, R]
93
104
```
94
-
In other words, an `Effect` is a generator that can yield values of type `A` or exceptions of type `E`, can be sent anything, and returns results of type `R`. Let's break that down a bit further:
105
+
In other words, an `Effect` is a generator that can yield values of type `A` or error values of type `E`, can be sent anything, and returns results of type `R`. Let's break that down a bit further:
95
106
96
107
- The type parameter `A` stands for _"Ability"_. This is the type of value, or types of values, that must be handled in order for the effect to produce its result.
When `hello_world`returns an`Effect[Greet, Never, None]`, it means that it depends on the `Greet` ability (`A` is parameterized with `Greet`). It doesn't produce errors (`E` is parameterized with `Never`), and it doesn't return a value (`R` is parameterized with `None`).
172
+
When `hello_world`has return type`Effect[Greet, Never, None]`, it means that it depends on the `Greet` ability (`A` is parameterized with `Greet`). It doesn't produce errors (`E` is parameterized with `Never`), and it doesn't return a value (`R` is parameterized with `None`).
162
173
163
174
To run an `Effect` that depends on abilities, you need to handle all of the abilities yielded by that effect. Abilities are handled using `stateless.Handler`, defined as:
In words: the effect passed to `run` must have had all of its abilities handled (except the built-in `Async` ability. Don't worry about this for now, we'll explain it later). The result of running `effect` is the result type `R`.
217
+
In words: In words: the effect passed to `run` must depend **only** on the built-in `Async` ability (Don't worry about the `Async` ability for now, we'll explain it later). All other abilities must have been handled before calling `run`. The result of running `effect` is the result type `R`.
207
218
208
219
If we try to do:
209
220
```python
@@ -355,6 +366,9 @@ This means that:
355
366
356
367
## Built-in Abilities
357
368
369
+
While you can write your own abilities and handlers, `stateless` supplies a few
370
+
built-in abilities.
371
+
358
372
### Need
359
373
360
374
`Need` is an ability for type-safe dependency injection. By "type-safe" we mean:
@@ -404,21 +418,31 @@ When trying to handle `Need[Console]` with `supply(MockConsole())`, you may need
404
418
405
419
To assist with type inference for type checkers with local type narrowing, stateless supplies a utility function `as_type`, that tells your type checker to treat a subtype as a supertype in a certain context.
0 commit comments