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
Copy file name to clipboardExpand all lines: README.md
+14-12Lines changed: 14 additions & 12 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -713,9 +713,9 @@ When you run `program.runSync()`, the output will be:
713
713
"world"
714
714
```
715
715
716
-
### Handling return values
716
+
### Chaining effected programs with `.andThen()` and `.tap()`
717
717
718
-
Sometimes, you may want to transform a program’s return value. Let’s revisit the `safeDivide` example:
718
+
Sometimes, you may want to transform a program’s return value, or chain another effected program after the current one. Let’s revisit the `safeDivide` example:
@@ -737,18 +737,20 @@ const some = <T>(value: T): Option<T> => ({ kind: "some", value });
737
737
const none:Option<never> = { kind: "none" };
738
738
```
739
739
740
-
We want to transform the return value of `safeDivide` into an `Option` type: if `safeDivide` returns a value normally, we return `some(value)`, otherwise, we return `none` (if the raise effect is triggered). This can be achieved with the map method:
740
+
We want to transform the return value of `safeDivide` into an `Option` type: if `safeDivide` returns a value normally, we return `some(value)`, otherwise, we return `none` (if the raise effect is triggered). This can be achieved with the `.andThen()` method:
Now, running `safeDivide2(1, 0).runSync()` will return `none`, while `safeDivide2(1, 2).runSync()` will return `some(0.5)`.
750
750
751
-
Besides `.map(handler)`, the `.tap(handler)` method offers a useful alternative when you want to execute side effects without altering the return value. Unlike `.map()`, `.tap()` ignores the return value of the handler function, ensuring the original value is preserved. This makes it ideal for operations like logging, where the action doesn’t modify the main data flow.
751
+
Similar to most other methods in tinyeffect, `.andThen()` can also be used with a generator function to chain another effected program, which can be incredibly useful in many scenarios. We’ll see many more examples of this in the following sections.
752
+
753
+
Besides `.andThen(handler)`, the `.tap(handler)` method offers a useful alternative when you want to execute side effects without altering the return value. Unlike `.andThen()`, `.tap()` ignores the return value of the handler function, ensuring the original value is preserved. This makes it ideal for operations like logging, where the action doesn’t modify the main data flow.
752
754
753
755
For instance, you can use `.tap()` to simulate a `defer` effect similar to Go’s `defer` statement:
@@ -1111,11 +1113,11 @@ const some = <T>(value: T): Option<T> => ({ kind: "some", value });
1111
1113
const none:Option<never> = { kind: "none" };
1112
1114
```
1113
1115
1114
-
In previous examples, we used `.map()` and `.terminate()` to transform the return value of `safeDivide` to an `Option` type. Now, we can abstract this logic into a reusable handler:
1116
+
In previous examples, we used `.andThen()` and `.terminate()` to transform the return value of `safeDivide` to an `Option` type. Now, we can abstract this logic into a reusable handler:
> The above example is purely for illustrative purposes and _should not_ be used in practice. While it demonstrates how effects can be handled, it mimics the behavior of a simple fib function with unnecessary complexity and overhead, which could greatly degrade performance.
1164
1166
1165
-
Understanding the definition of `fib2` may take some time, but it serves as an effective demonstration of working with effects without generators. The expression `fib2(n - 1).map((a) => fib2(n - 2).map((b) => a + b))` can be interpreted as follows: “After resolving `fib2(n - 1)`, assign the result to `a`, then resolve `fib2(n - 2)` and assign the result to `b`. Finally, return `a + b`.”
1167
+
Understanding the definition of `fib2` may take some time, but it serves as an effective demonstration of working with effects without generators. The expression `fib2(n - 1).andThen((a) => fib2(n - 2).andThen((b) => a + b))` can be interpreted as follows: “After resolving `fib2(n - 1)`, assign the result to `a`, then resolve `fib2(n - 2)` and assign the result to `b`. Finally, return `a + b`.”
1166
1168
1167
-
It’s important to note that the first `.map()` call behaves like a `flatMap` operation, as it takes a function that returns another `Effected` instance and “flattens” the result. However, in tinyeffect, the distinction between `map` and `flatMap` is not explicit — `.map()` will automatically flatten the result if it’s an `Effected` instance. This allows for seamless chaining of `.map()` calls as needed.
1169
+
It’s important to note that the first `.andThen()` call behaves like a `flatMap` operation, as it takes a function that returns another `Effected` instance and “flattens” the result. However, in tinyeffect, the distinction between `map` and `flatMap` is not explicit — `.andThen()` will automatically flatten the result if it’s an `Effected` instance, just like `Promise.prototype.then()` in JavaScript. This allows for seamless chaining of `.andThen()` calls as needed.
0 commit comments