affection: Declarative Side Effects
source link: https://www.tuicool.com/articles/hit/AvmiUnY
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Affection
Declarative side-effects
npm install affection
Affection is a library for describing side-effects as plain data and providing composition utilities. This project aims to improve on similar libraries by not using generators.
Generators make testing difficult in that:
next()
So Affection is all about functions, with the goals:
- Improve testability through the use of pure functions.
- Improve code reuse through la-a-carte composition of side-effects.
Let's see how we do.
Examples
This first example does not use any composition.
import { run, call, callMethod } from 'affection' const getJSON = url => [ call(fetch, url), resp => [callMethod(resp, 'json')] ] async function main () { const payload = await run(getJSON('http://example.com')) console.log(payload) }
This second example does the same as the first. Here we are using the composition utilities.
import { step, runStep, batchSteps, call, callMethod } from 'affection' const fetchUrl = url => call(fetch, [url]) const readJSON = resp => callMethod(resp, 'json') const getJSON = batchSteps([fetchUrl, readJSON].map(step)) async function main () { const payload = await runStep(getJSON, 'http://example.com') console.log(payload) }
Documentation
The package contains the following:
Effects
Seefor adding more.
Execution
Composition
-
mapStep(step, transform)
-
runStep(step, input[, handle])
call
call(func: function, args: Array<any>, context: any): Effect
Describes a function call of func.apply(context, args)
.
callMethod
callMethod(obj: any, method: String, args: Array<any>): Effect
Describes a method call of obj[method].apply(obj, args)
all
all(effects: Array<Effect>): Effect
Describes combining effects. Like Promise.all
.
race
race(effects: Array<Effect>): Effect
Describes racing effects. Like Promise.race
.
itself
itself(value: any): Effect
Describes a value. This is an identity function for Effects.
defaultHandle
defaultHandle(effect: Effect, handle: function): any
Performs the action described by a particular effect. defaultHandle
provides the handling for the effects included in Affection.
To add more, create a new handle that wraps defaultHandle
and pass that to run
.
For example, say we want to add a timeout effect:
import { defaultHandle } from 'affection' export function timeout (duration) { return { type: 'timeout', duration } } export function myHandle (effect, handle) { if (effect.type === 'timeout') { return new Promise(resolve => setTimeout(resolve, effect.duration)) } return defaultHandle(effect, handle) } // Later... async function main () { await run([timeout(1000)], myHandler) // Will have waited a second }
run
run(plan: [Effect, function?], handle: function = defaultHandle): any
Executes a plan.
A plan is an array where the first element is an Effect to be handled using handle
and the second element is a function to call with the result of the Effect.
If the function is not provided, execution terminates and the result is returned.
step
step(makeEffect: any -> Effect): Step
Creates a step.
A step is a means of encapsulating an effect without needing a plan (as described by run
).
This is hard to understand without an understanding of how run
works.
The run
function is recursively executing plans until there is nothing more to do.
A step is a way of saying, "Execute this effect; I don't know what happens with the result."
This is for code reuse: effects should be decoupled from their consumers.
For more clarity, let's look at the step
function:
const step = makeEffect => next => input => [makeEffect(input), next]
We define our makeEffect
without needing to know the consumer.
The next
is what will consume the result.
Later, steps are composed when the consumers are known.
Finally, the step is given an input
to build its effect.
In summary, steps decouple:
makeEffect next input
mapStep
mapStep(step: Step, transform: function): Step
Creates a new step which will return the result of transform
called with the input to the step
makeEffect
and the result of the Effect.
This is good for passing along context without mucking up simple steps. For example, we are building a dictionary of the most used word for each country. We want to retain the country we are querying about in the result.
const getMostUsedWordInCountry = country => call(MyAPI, country) const countryWordStep = step(getMostUsedWordInCountry) const getCountryWord = mapStep(countryWordStep, (result, country) => ({ country, word: result })) runStep(getCountryWord, 'Canada').then(result => { console.log(result) // => { country: 'Canada', word: 'Sorry' } })
batchSteps
batchSteps(steps: Array<Step>): Step
Creates a new step which will call each step passing the result of first step to the next and so on.
runStep
runStep(step: Step, input: any, handle: function = defaultHandle): any
Executes a step
with a given input
.
Uses run
so handle
works in the same way.
Recommend
-
6
Vaccines Are Here. We Have to Talk About Side EffectsDisinformation could thwart distribution before government messages have a chance to push back. Debunking might turn out to be everyone’s job.
-
4
Eyas's BlogOccasional musings on software development, tech, the Middle East, and anything else.My previous articles on
-
5
Jetpack Compose Side-Effects — LaunchedEffectThe dictionary defines the term side-effectas an undesirable effect. While this applies to compose side-effects as well, sometimes they are r...
-
8
Jetpack Compose Side-Effects II — rememberCoroutineScopeIn the previous part, we talked about how LaunchedEffect can be used to launch coroutines from composable and not worry about leaking the task. LaunchedEffect l...
-
4
rails 7 Published on 22 September 2021 22 September 2021 • 3 min read Side effects of Active Record's...
-
2
Mechanisms Behind Vaccine Side-Effects: The Science That Causes That Sore Arm After receiving a vaccination shot, it’s likely that we’ll feel some side-effects. These can range from merely a s...
-
4
Introduction to JavaScript Functions A function allows us to place code logically to execute a task. Functions are first-class citizens in the JavaScript programming language. You can create, modify a function, u...
-
2
Have you found side-effects a problem by increasing complexity in your code bases? Given that “Out of the Tarpit” says side-effects begat complexity, it doesn’t seem like most people outside of functional program...
-
4
Glucofort Reviews – Negative Customer Complaints and Side Effects? This can...
-
2
How Side Effects Work in FPAndre Popovitch (aka Chad Nauseam)When you think about functional programming, you might think of banning mutation, or of functions without side...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK