kojima/README.md

259 lines
5.6 KiB
Markdown

# kojima
a small functional/monad library
# Usage
## Example
```js
import { Option, Some, None, Result, Ok, Err } from 'kojima'
const maybe = Option.of('thing')
maybe.isSome() // true
const isnt = maybe.chain(None).map(_x => 'other') // None
isnt.isSome() // false
const result = Result.of('3:41am')
result.isOk() // true
result.chain(() => Err(new Error(-Infinity)))
.map(_x => '4:10am')
.chain(Ok)
result.isErr() // true
// crimes!
None == None() // true
```
## Documentation
### curry
> (* -> a) -> (* -> a)
Returns a curried equivalent of the provided function.
```js
import { curry } from './curry.js'
const add = (a, b, c) => a + b + c
const curriedAdd = curry(add)
const add1 = curriedAdd(1)
const add3 = add1(2)
const add4 = curriedAdd(2, 2)
const six = add3(3) // 6
const eight = add4(2) // 7
const twelve = curriedAdd(4, 4, 4) // 12
```
### Option
> Option\<T\> = Some\<T\> | None
Represents a value which may not exist.
#### Methods
##### of :: Option f => a -> f a
> Option.of\<a\>(value: a) -> Option\<a\>
Creates a new `Some<T>` from `T`
```js
const some = Option.of(1) // Some<number>(1)
```
##### zero :: Option f => () -> f a
> Option.zero() -> Option\<()\>
Creates a new `Err<()>`
```js
const none = Option.zero() // None
```
##### chain :: Option m => m a ~> (a -> m b) -> m b
> Option\<T\>.chain\<U\>(fn: (value: T) -> Option\<U\>) -> Option\<U\>
Transform a `Option<T>` into `Option<U>` by applying `fn(T) -> Option<U>`.
```js
const some = Option.of(1)
const next = some.chain(x => Some(`value ${x}`)) // Some<string>('value 1')
None.chain(x => Some(`value ${x}`)) // None
const none = some.chain(None) // None
none.chain(() => Some(1)) // None
```
##### map :: Option f => f a ~> (a -> b) -> f b
> Option\<T\>.map\<U\>(fn: (value: T) -> U) -> Option\<U\>
##### alt :: Option f => f a ~> f a -> f a
> Option\<T\>.alt(other: Option\<T\>) -> Option\<T\>
Choose between either the first or second `Option` based on existence.
```js
const some = Option.of(1)
const none = Option.zero()
some.alt(none) // Some<number>(1)
none.alt(some) // Some<number>(1)
some.alt(Some(2)) // Some<number>(1)
Some(2).alt(some) // Some<number>(2)
none.alt(None) // None
None.alt(none) // None
```
##### fold :: Option f => f a ~> ((b, a) -> b, b) -> b
> Option\<T\>.fold\<U\>(fn: ((acc: U, value: T) -> U, initial: U) -> U) -> U
Fold over a `Option`, accumulating the value. This is `unwrap_or_default` in Rust.
```js
const some = Some(1)
some.fold((acc, x) => x), 2) // 1
some.fold((acc, x) => acc), 2) // 2
const none = Option.zero()
none.fold((acc, x) => x, 2) // 2
```
##### isSome :: Option f => () -> boolean
> Option\<T\>.isSome() -> boolean
Returns a boolean based on whether the Option is `Some<T>`
```js
Some(1).isSome() // true
None.isSome() // false
```
##### isNone :: Option f => () -> boolean
> Option\<T\>.isNone() -> boolean
Returns a boolean based on whether the Option is `None`
```js
Some(1).isNone() // false
None.isNone() // true
```
### Result
> Result<T, E> = Ok\<T\> | Err\<E\>
Represents a value which may fail.
#### Methods
##### of :: Result f => a -> f a
> Result.of\<a\>(value: a) -> Result\<a, ()\>
Creates a new `Ok<T>` from `T`
```js
const ok = Result.of(1) // Ok<number>(1)
```
##### zero :: Result f => () -> f a
> Result.zero() -> Result\<(), ()\>
Creates a new `Err<()>`
```js
const err = Result.zero() // Err<()>()
```
##### chain :: Result m => m a ~> (a -> m b) -> m b
> Result\<T, E\>.chain\<U\>(fn: (value: T) -> Result<U, E>) -> Result\<U, E\>
Transform a `Result<T, E>` into `Result<U, E>` by applying `fn(T) -> Result<U, E>`.
```js
const ok = Result.of(1)
const next = ok.chain(x => Ok(`value ${x}`)) // Ok<string>('value 1')
Err(0).chain(x => Ok(1)) // Err(0)
const err = next.chain(() => Err(0)) // Err(0)
err.chain(() => Ok(1)) // Err(0)
```
##### map :: Result f => f a ~> (a -> b) -> f b
> Result\<T, E\>.map\<U\>(fn: (value: T) -> U) -> Result\<U, E\>
Transform a `Result<T, E>` into a `Result<U, E>` by applying `fn(T) -> U`
```js
const ok = Result.of(1)
const next = ok.map(x => `value ${x}`) // Ok<string>('value 1')
Err(0).map(x => Ok(1)) // Err(0)
```
##### alt :: Result f => f a ~> f a -> f a
> Result\<T, E\>.alt(other: Result\<T, E\>) -> Result\<T, E\>
Choose between either the first or second `Result` based on success.
```js
const ok = Result.of(1)
const err = Result.zero()
ok.alt(err) // Ok<number>(1)
err.alt(ok) // Ok<number>(1)
ok.alt(Ok(2)) // Ok<number>(1)
Ok(2).alt(ok) // Ok<number>(2)
err.alt(Err(new Error('wont see this'))) // Err<()>()
Err(new Error('hi! :3')).alt(err) // Err<Error>(new Error('hi! :3'))
```
##### fold :: Result f => f a ~> ((b, a) -> b, b) -> b
> Result\<T, E\>.fold\<U\>(fn: ((acc: U, value: T) -> U, initial: U) -> U) -> U
Fold over a `Result`, accumulating the value. This is `unwrap_or_default` in Rust.
```js
const ok = Ok(1)
ok.fold((acc, x) => x), 2) // 1
ok.fold((acc, x) => acc), 2) // 2
const err = Result.zero()
err.fold((acc, x) => x, 2) // 2
```
##### bimap :: Result f => f a c ~> (a -> b, c -> d) -> f b d
> Result\<T1, E1\>.bimap\<T2, E2\>(x: (value: T1) -> T2, y: (error: E1) -> E2) -> Result\<T2, E2\>
```js
const ok = Ok(1)
ok.bimap(
x => x + 1,
y => y * 2
) // Ok(2)
const err = Err(4)
err.bimap(
x => x + 1,
y => y * 2
) // Err(8)
```
##### isOk :: Result f => () -> boolean
> Result\<T, E\>.isOk() -> boolean
Returns a boolean based on whether the Result is `Ok<T>`
```js
Ok(1).isOk() // true
Err(1).isOk() // false
```
##### isErr :: Result f => () -> boolean
> Result\<T, E\>.isErr() -> boolean
Returns a boolean based on whether the Result is `Err<E>`
```js
Ok(1).isErr() // false
Err(1).isErr() // true
```