exalted.future
Experimental
A javascript and typescript monadic library & functional fun. fantasy-land compliant, mostly.
The style of monad object is inspired by DrBoolean course on egghead.io.
The choice for cata
, encase
, head
, tail
, last
is inspired by rametta's take on monads in pratica.
This is, in many ways, an evolution of oncha which I wrote with other people many years ago and is no longer maintained.
Install
yarn add exalted.future
Types
- There is a divergence from fantasy-land where
reduce
is named cata
and loosely based on daggy's union types. fold
always folds on identity a => a
, except when it does not like with the Future
.Maybe.map
will return Nothing if the callback function returns null. In other words Just(null)
is impossible, unless you call the 'static' constructor like this Just.of(null)
. See this pr for some explanation.- Left is not 100% applicative.
All
These functions are available on all types.
ap
Apply
chain :: (a -> b) -> b
Id(5).chain(a => Id(a))
Id(Id(5)).chain(a => a)
equals
Setoid
equals :: Id -> Boolean
Id(1).equals(Id(1))
Id(2).equals(Id(1))
Id(2).equals(Id(1)) === Id(1).equals(Id(1))
chain
Chain
chain :: (a -> b) -> b
Id(5).chain(a => Id(a))
Id(Id(5)).chain(a => a)
map
Functor
map :: (a -> b) -> Id of b
Id(7).map(a => a * 2)
of
Applicative
of :: a -> Id of a
Id(5).of(6)
Id(5).of(Id(6))
fold
Foldable
fold :: (a -> b) -> b
Id(5).fold()
Id(5).fold()
cata
Foldable
cata :: ({ Left: () -> b, Right -> a -> a }) -> a | b
Id(5).cata({
Right: a => a
})
Id(5).cata({
Right: a => a + 1
})
Right(5).cata({
Left: a => 8
Right: a => a + 1
})
Left(5).cata({
Left: a => a + 1
Right: a => 8
})
inspect
inspect :: () -> String
Id(5).inspect()
Id
Identity monad.
Id(5)
.map(num => num * 7)
.map(num => num - 1)
.cata({
Right: a => a
})
Maybe
Maybe monad.
Maybe('Hello exalted one')
.map(sentence => sentence.toUpperString())
.map(sentence => `${sentence}!`)
.cata({
Right: console.log
})
Maybe(null)
.map(sentence => sentence.toUpperString())
.alt(() => 'Maybe received a null')
.cata({
Right: console.log
})
alt
Sets the value to cata on.
alt :: Any -> Nothing of Any
Maybe(1).alt(5).cata({
Right: a => a
})
Maybe(null).alt(5).cata({
Right: a => a
})
cata
Foldable
cata :: ({ Left: () -> b, Right: a -> b }) -> a|b
Maybe(5).cata({
Right: a => a
})
Maybe(5).cata({
Left: () => { }
Right: a => a + 1
})
Maybe(null).cata({
Left: () => 'there was a null'
Right: a => a + 1
})
Either
An Either monad and nullable, Left, Right.
nullable('Hello')
.cata({
Left: () => 'Oops',
Right: val => `${val} world!`
})
nullable(null)
.cata({
Left: () => 'Oops',
Right: val => `${val} world!`
})
const extractEmail = obj => obj.email ? Right(obj.email) : Left()
extractEmail({ email: 'test@example.com' }
.map(extractDomain)
.cata({
Left: () => 'No email found!',
Right:x => x
})
extractEmail({ name: 'user' }
.map(extractDomain)
.cata({
Left: () => 'No email found!',
Right: x => x
})
cata
Foldable - Folds foldable object.
cata :: ({ Left: () -> b, Right -> a -> a }) -> a | b
Right(5).cata({
Left: () => 1,
Right: a => a + 2
})
Left(5).cata(a => a + 1)
Future
A Future monad for async computation.
Future((reject, resolve) => resolve('Yay'))
.map(res => res.toUpperString())
.fork(
err => log(`Err: ${err}`),
res => log(`Res: ${res}`))
Future.fromPromise(fetch('https://api.awesome.com/catOfTheDay'))
.fork(
err => log('There was an error fetching the cat of the day :('),
cat => log('Cat of the day: ' + cat))
Future.fromPromise(fetch('https://api.awesome.com/catOfTheDay'))
.chain(cat => Future.fromPromise(fetch(`https://api.catfacts.com/${cat}`)))
.fork(
err => log('There was an error fetching the cat of the day :('),
facts => log('Facts for cat of the day: ' + facts))
all
Forks all the futures.
all :: ([Futures]) -> b
Future.all(
Future.of('apple'),
Future((left, right) => setTimeout(() => right('orange'), 1000)),
Future.of('lemon')
).fork(
() => (),
([ apple, orange, lemon ]) =>
)
fold
Foldable
Folds on identity.
fold :: (a -> b) -> b
Future.of(5).fold()
fork
Executes the Future
returning a Future
of the resuts.
fork :: (a -> a, b -> b) -> Future of a | b
Future((left, right) => right(5)).fork(a => a, a => a)
Future((left, right) => left(Error('this is an error'))).fork(a => a)
Higher Order Utilities
compose
Compose takes n functions as arguments and return a function.
const transform = compose(sentence => sentence.toUpperString(), sentence => `${sentence}!`)
const logTransform = compose(log, transform)
logTransform('Hello exalted one')
compose(path.normalize, path.join)('./exalted', '/one')
map
Map as partial application and first class with arity support.
map(a => a + 1, a => a * 3)([1, 2, 3])
head, tail, last
Returns a Maybe.
head([1,2])
head([])
tail([1,2,3])
tail([])
last([1,2,3])
last([])
encase, encaseEither
Returns Left | Right
.
encase(() => JSON.parse('["foo","bar","baz"]'))
encase(() => JSON.parse('['))
encaseEither(() => JSON.parse('["foo","bar","baz"]'))
encaseEither(() => JSON.parse('['))