-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #24 from ENvironmentSet/add-fp-ts-monad-instance
Make `Effectful` to be monad
- Loading branch information
Showing
4 changed files
with
143 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# `hyogwa/monad` | ||
|
||
Module implementing functions needed for `Effectful` to be monad. Utilize functions here to define monad instance of | ||
`Effectful` when using other functional programming libraries like `fp-ts` and `fun`. | ||
|
||
> **⚠️ CAUTION**: Strictly speaking, `Effectful` is not a monad. Evaluating the same effectful computation multiple times | ||
> will produce unsound result. Have your code run(via `yield*`, `handle` or runners.) effectful computations only once per instance. | ||
## `map<E, A, B>(f: (a: A) => B, computation: Effectful<E, A>): Effectful<E, B>` | ||
|
||
Applies function to result of a computation. | ||
|
||
## `map<A, B>(f: (a: A) => B): <E>(computation: Effectful<E, A>) => Effectful<E, B>` | ||
|
||
Lifts given function to work with effectful computations instead of plain values | ||
|
||
## `of<T>(value: T): Effectful<never, T>` | ||
|
||
Makes computation of the given value | ||
|
||
## `ap<E, A, B>(wrappedF: Effectful<E, (a: A) => B>, computation: Effectful<E, A>): Effectful<E, B>` | ||
|
||
Applies function inside effectful computation to result of another computation. | ||
|
||
## `ap<E1, A, B>(wrappedF: Effectful<E1, (a: A) => B>): <E2>(computation: Effectful<E2, A>) => Effectful<E1 | E2, B>` | ||
|
||
Unwrap function inside effectful computation as function for effectful computations. | ||
|
||
## `chain<E, A, B>(f: (a: A) => Effectful<E, B>, computation: Effectful<E, A>): Effectful<E, B>` | ||
|
||
Applies effectful function to effectful computation. | ||
|
||
## `chain<E1, A, B>(f: (a: A) => Effectful<E1, B>): <E2>(computation: Effectful<E2, A>) => Effectful<E1 | E2, B>` | ||
|
||
Lifts effectful function to be function of effectful computations. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import { Effectful } from './core'; | ||
|
||
/** | ||
* Applies function to result of a computation | ||
* | ||
* @beta | ||
* | ||
* @param f - A function to apply | ||
* @param computation - A computation whose result will be applied | ||
* @returns A computation mapped by `f` | ||
*/ | ||
export function map<E, A, B>(f: (a: A) => B, computation: Effectful<E, A>): Effectful<E, B> | ||
/** | ||
* Lifts given function to work with effectful computations instead of plain values | ||
* | ||
* @beta | ||
* | ||
* @param f - A function to lift | ||
* @returns lifted function | ||
*/ | ||
export function map<A, B>(f: (a: A) => B): <E>(computation: Effectful<E, A>) => Effectful<E, B> | ||
export function map<E, A, B>(f: (a: A) => B, computation?: Effectful<E, A>) | ||
: Effectful<E, B> | (<E>(computation: Effectful<E, A>) => Effectful<E, B>) { | ||
if (!computation) return function* (computation) { return f(yield* computation) } | ||
else return (function* () { return f(yield* computation) })() | ||
} | ||
|
||
/** | ||
* Makes computation of the given value | ||
* | ||
* @beta | ||
* | ||
* @param value | ||
* @returns pure computation only producing the given value | ||
*/ | ||
export function* of<T>(value: T): Effectful<never, T> { | ||
return value | ||
} | ||
|
||
/** | ||
* Applies function inside effectful computation to result of another computation | ||
* | ||
* @beta | ||
* | ||
* @param wrappedF - An effectful computation wrapping a function | ||
* @param computation - An effectful computation whose result will be applied | ||
*/ | ||
export function ap<E, A, B>(wrappedF: Effectful<E, (a: A) => B>, computation: Effectful<E, A>): Effectful<E, B> | ||
/** | ||
* Unwrap function inside effectful computation as function for effectful computations | ||
* | ||
* @beta | ||
* | ||
* @param wrappedF - A function to unwrap | ||
* @returns an unwrapped function for effectful computations | ||
*/ | ||
export function ap<E1, A, B>(wrappedF: Effectful<E1, (a: A) => B>) | ||
: <E2>(computation: Effectful<E2, A>) => Effectful<E1 | E2, B> | ||
export function ap<E, A, B>(wrappedF: Effectful<E, (a: A) => B>, computation?: Effectful<E, A>) | ||
: Effectful<E, B> | (<E2>(computation: Effectful<E2, A>) => Effectful<E | E2, B>) { | ||
if (!computation) return function* (computation) { | ||
const f = yield* wrappedF | ||
const a = yield* computation | ||
|
||
return f(a) | ||
} | ||
else return (function* () { | ||
const f = yield* wrappedF | ||
const a = yield* computation | ||
|
||
return f(a) | ||
})() | ||
} | ||
|
||
/** | ||
* Applies effectful function to effectful computation | ||
* | ||
* @beta | ||
* | ||
* @param f - An effectful function to apply | ||
* @param computation - An effectful computation to be applied | ||
*/ | ||
export function chain<E, A, B>(f: (a: A) => Effectful<E, B>, computation: Effectful<E, A>): Effectful<E, B> | ||
/** | ||
* Lifts effectful function to be function of effectful computations | ||
* | ||
* @beta | ||
* | ||
* @param f - An effectful function to lift | ||
*/ | ||
export function chain<E1, A, B>(f: (a: A) => Effectful<E1, B>) | ||
: <E2>(computation: Effectful<E2, A>) => Effectful<E1 | E2, B> | ||
export function chain<E, A, B>(f: (a: A) => Effectful<E, B>, computation?: Effectful<E, A>) | ||
: Effectful<E, B> | (<E2>(computation: Effectful<E2, A>) => Effectful<E | E2, B>) { | ||
if (!computation) return function* (computation) { | ||
const a = yield* computation | ||
|
||
return yield* f(a) | ||
} | ||
else return (function* () { | ||
const a = yield* computation | ||
|
||
return yield* f(a) | ||
})() | ||
} |