exalted.future
Experimental
A javascript and typescript monadic library & functional fun. fantasy-land compliant, mostly.
Install
yarn add exalted.future
Types
- There is a divergence from fantasy land where
reduce
is named cata
and is more similar to daggy than the typical reduce. fold
always folds on identity a => a
.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.
cata
and some new utilities such as encase
, head
, tail
, get
are inspired by rametta's take on monads in pratica.- This is, in many, a revision or evolution of oncha which I wrote with other people many years ago and is no longer maintained.
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()
fold
Foldable
fold :: (a -> b) -> 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)
.fold({
Right: a => a
})
Maybe
Maybe monad.
Maybe('Hello exalted one')
.map(sentence => sentence.toUpperString())
.map(sentence => `${sentence}!`)
.fold({
Right: console.log
})
Maybe(null)
.map(sentence => sentence.toUpperString())
.alt(() => 'Maybe received a null')
.fold({
Right: console.log
})
alt
Sets the value to fold on.
alt :: Any -> Nothing of Any
Maybe(1).alt(5).fold({
Right: a => a
})
Maybe(null).alt(5).fold({
Right: a => a
})
fold
Foldable
fold :: (a -> b) -> b
Maybe(5).fold({
Right: a => a
})
Maybe(5).fold({
Left: () => { }
Right: a => a + 1
})
Maybe(null).fold({
Left: () => 'there was a null'
Right: a => a + 1
})
Either
An Either monad and nullable, Left, Right.
nullable('Hello')
.fold({
Left: () => 'Oops',
Right: val => `${val} world!`
})
nullable(null)
.fold({
Left: () => 'Oops',
Right: val => `${val} world!`
})
const extractEmail = obj => obj.email ? Right(obj.email) : Left()
extractEmail({ email: 'test@example.com' }
.map(extractDomain)
.fold({
Left: () => 'No email found!',
Right:x => x
})
extractEmail({ name: 'user' }
.map(extractDomain)
.fold({
Left: () => 'No email found!',
Right: x => x
})
fold
Foldable - Folds foldable object.
fold :: ({ Left: () -> b, Right -> a -> a }) -> a | b
Right(5).fold({
Left: () => 1,
Right: a => a + 2
})
Left(5).fold(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
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
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('['))