Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
exalted.future
Advanced tools
Exalted monadic library & functional fun, fantasy-land compliant, mostly.
Experimental The api can change between versions.
A javascript monadic library & functional fun. fantasy-land compliant, mostly.
The style of monad object is inspired by DrBoolean course on egghead.io and his book Mostly adequate guide to FP.
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.
One of the main goals of the exalted.future is to make it possible to rely on natural transformation when composing Monads. So that you can write in one continuous flow your program, agnostic of the Monad you are working with. That is why flatMap
, mapReduce
, reduce
, fold
, and fork
use the same language, cata
. You can always call cata on an object, and it will compute your results. The following example attempts to illustrate that. Regardless that the fetch succeeds or fails the outcome will be the same, indifferent to calling cata
on Maybe, Either (Left|Right), or Future.
Future.promise(fetch('https://jsonplaceholder.typicode.com/todos/1'))
.chain(response => Either.encase(() => response.json()))
.chain(Future.promise)
.chain(Maybe)
.map(todo => todo.title)
.map(t => t.toUpperCase())
.cata({
Left: e => console.log('oops', e),
Right: json => console.log(json)
})
yarn add exalted.future
Name | Apply | Applicative | Setoid | Foldable | Functor | Monad | Chain |
---|---|---|---|---|---|---|---|
Either | ✔︎ | ✔︎ | ✔︎ | ✔︎ | ✔︎ | ✔︎ | ✔︎ |
Future | ✔︎ | — | ✔︎ | ✔︎ | ✔︎ | — | ✔︎ |
Identity | ✔︎ | ✔︎ | ✔︎ | ✔︎ | ✔︎ | ✔︎ | ✔︎ |
Maybe | ✔︎ | ✔︎ | ✔︎ | ✔︎ | ✔︎ | ✔︎ | ✔︎ |
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.bimap
, swap
, fold
, foldr
, foldf
.A Future monad for async computation. Left
is reject and Right
is resolve. Because Right
is always right and Left is not.
// Basic usage
Future((err, ok) => ok('Yay'))
.map(res => res.toUpperString())
.cata({
Left: err => log(`Err: ${err}`),
Right: res => log(`Res: ${res}`)
})
//=> 'YAY'
// Handle promises
Future.promise(fetch('https://api.awesome.com/catOfTheDay'))
.cata({
Left: err => log('There was an error fetching the cat of the day :('),
Right: cat => log('Cat of the day: ' + cat)
})
//=> 'Cat of the day: Garfield'
// Chain http calls
Future.promise(fetch('https://api.awesome.com/catOfTheDay'))
.chain(cat => Future.promise(fetch(`https://api.catfacts.com/${cat}`)))
.cata({
Left: err => log('There was an error fetching the cat of the day :('),
Right: facts => log('Facts for cat of the day: ' + facts)
})
//=> 'Facts for cat of the day: Garfield is awesome.'
Concats all the results form the list of futures.
all :: ([Futures]) -> b
Future.all(
Future.of('apple'),
Future((left, right) => setTimeout(() => right('orange'), 1000)),
Future.of('lemon')
).cata({
Left: () => (),
Right: ([ apple, orange, lemon ]) => console.log(apple, orange, lemon)
}) //=> apple, orange, lemon
Identity monad.
Id(5)
.map(num => num * 7)
.map(num => num - 1)
.cata({
Right: a => a
})
//=> 34
Maybe monad.
// Maybe of a string
Maybe('Hello exalted one')
.map(sentence => sentence.toUpperString())
.map(sentence => `${sentence}!`)
.cata({
Right: console.log
})
//=> 'HELLO EXALTED ONE!'
// Maybe of nothing
Maybe(null)
.map(sentence => sentence.toUpperString())
.alt(() => 'Maybe received a null')
.cata({
Right: console.log
})
//=> 'Maybe received a null'
An Either monad and nullable, Left, Right.
nullable('Hello') // this will return a Right('Hello')
.cata({
Left: () => 'Oops',
Right: val => `${val} world!`
})
//=> 'Hello world!'
nullable(null) // this will return a Left()
.cata({
Left: () => 'Oops',
Right: val => `${val} world!`
})
//=> 'Oops'
const extractEmail = obj => obj.email ? Right(obj.email) : Left()
extractEmail({ email: 'test@example.com' }
.map(extractDomain)
.cata({
Left: () => 'No email found!',
Right:x => x
})
//=> 'example.com'
extractEmail({ name: 'user' }
.map(extractDomain) // this will not get executed
.cata({
Left: () => 'No email found!',
Right: x => x
})
//=> 'No email found!'
The following functions are common to all monads types.
Sets the value to cata on.
alt :: Any -> Nothing of Any
Maybe(1).alt(5).cata({
Right: a => a
})
//=> 1
Maybe(null).alt(5).cata({
Right: a => a
})
//=> 5
chain :: (a -> b) -> b
Id(5).chain(a => Id(a))
//=> Id(5)
// You can use chain to join the monads.
Id(Id(5)).chain(a => a)
//=> Id(5)
cata :: ({ Left: () -> b, Right -> a -> a }) -> a | b
Id(5).cata({
Right: a => a
})
//=> 5
Id(5).cata({
Right: a => a + 1
})
//=> 6
Right(5).cata({
Left: a => 8 // ignored
Right: a => a + 1
})
//=> 6
Left(5).cata({
Left: a => a + 1
Right: a => 8 // ignored
})
//=> 6
Maybe(5).cata({
Right: a => a
})
//=> 5
Maybe(5).cata({
Left: () => { } // not called
Right: a => a + 1
})
//=> 6
Maybe(null).cata({
Left: () => 'there was a null'
Right: a => a + 1 // not called
})
//=> there was a null
Right(5).cata({
Left: () => 1,
Right: a => a + 2
})
//=> 7
Left(5).cata(a => a + 1)
//=> 6
chain :: (a -> b) -> b
Id(5).chain(a => Id(a))
//=> Id(5)
// You can use chain to join the monads.
Id(Id(5)).chain(a => a)
//=> Id(5)
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')
//=> 'HELLO EXALTED ONE!'
// supports miltiple arguments
compose(path.normalize, path.join)('./exalted', '/one')
//=> './exalted/one'
equals :: Id -> Boolean
Id(1).equals(Id(1))
//=> true
Id(2).equals(Id(1))
//=> false
Id(2).equals(Id(1)) === Id(1).equals(Id(1))
//=> false
inspect :: () -> String
Id(5).inspect()
//=> Id(5)
map :: (a -> b) -> Id of b
Id(7).map(a => a * 2)
//=> Id(14)
Map as partial application and first class with arity support.
map(a => a + 1, a => a * 3)([1, 2, 3])
//=> [4, 7, 10]
of :: a -> Id of a
Id(5).of(6)
//=> Id(6)
Id(5).of(Id(6))
//=> Id(Id(6))
Returns a Maybe.
head([1,2])
//=> Just(1)
head([])
//=> Nothing()
tail([1,2,3])
//=> Just([2,3])
tail([])
//=> Nothing()
last([1,2,3])
//=> Just(3)
last([])
//=> Nothing()
Returns Left | Right
.
Maybe.encase(() => JSON.parse('["foo","bar","baz"]'))
//=> Just(['foo','bar','baz'])
Maybe.encase(() => JSON.parse('['))
//=> Nothing()
Either.encase(() => JSON.parse('["foo","bar","baz"]'))
//=> Right(['foo','bar','baz'])
Either.encase(() => JSON.parse('['))
//=> Left(new SyntaxError ('Unexpected end of JSON input'))
FAQs
Exalted monadic library & functional fun, fantasy-land compliant, mostly.
We found that exalted.future demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.