How to augment an existing function so it lazily unwraps its arguments? - javascript

I have a bunch of regular utility functions. I want to convert those functions to ones that accept arguments wrapped in functions (to introduce a side-effect when a value is used).
// Some utility function:
const pick = (takeLeft, left, right) =>
takeLeft ? left : right;
// Some wrapper with a side-effect
const Watched = x => () => {
console.log(`Value ${x} is used`);
return x;
};
// I want this to log:
// Value true is used
// Value L is used
const myPick = runWithWatchedValues(
pick,
Watched(true), Watched("L"), Watched("R")
);
I’m looking for help implementing runWithWatchedValues, or for somebody to explain me why it can’t be done.
Attempts
The problem with unwrapping the values before calling the inner function:
// An incorrect attempt: (also logs "R")
const runWithWatchableValues = (f, ...args) =>
f(...args.map(w => w()));
I tested if calling the function with apply and some special getters would work, but it turns out this does exactly the same 😅.
// Another incorrect attempt: (also logs "R")
const runWithWatchableValues = (f, ...watched) => {
const args = watched.reduce(
(acc, get, i) => Object.defineProperty(acc, i, { get }),
[]
);
return f.apply(null, args);
};
My current solution is to manually rewrite utility functions. I.e.:
const pick = (takeLeft, left, right) =>
takeLeft ? left : right;
const pickW = (takeLeft, left, right) =>
takeLeft() ? left() : right();
// Correctly logs true and L
pickW(Watched(true), Watched("L"), Watched("R"));
I’d rather not maintain my own library of utility functions when there are well documented and well maintained libraries like ramda or lodash…
The question(s)
I’m starting to feel like the thing I want just is just not something the language can do… But I hope I’m wrong!
Is it theoretically possible to write runWithWatchableValues and get the desired result?
If yes, how?
If no, is there another automated way (Babel/build steps?) you can think of to prevent having to manually rewrite pick to work with wrapped values?
“This is an x/y problem!”
It might be, but I wanted to keep it simple. Here’s what I’m really doing (using knockout.js):
const pick = (takeLeft, left, right) =>
takeLeft ? left : right;
const takeLeft = ko.observable(true);
const left = ko.observable("L");
const right = ko.observable("R");
// BROKEN: The easy, but wrong implementation:
const myPick = ko.pureComputed(
() => pick(takeLeft(), left(), right())
);
console.log(
"Naive approach:",
myPick(), // Right: "L"
myPick.getDependenciesCount() // Wrong: 3
);
// The dependency on `right` will mean that updating
// it will cause myPick to re-evaluate, even though we
// already know its return value won't change.
// FIXED: The manual fix:
const pickObs = (takeLeft, left, right) =>
takeLeft() ? left() : right();
const myCorrectPick = ko.pureComputed(
() => pickObs(takeLeft, left, right)
);
console.log(
"With manual rewrite:",
myCorrectPick(), // Right: "L"
myCorrectPick.getDependenciesCount() // Right: 2
);
// Changing `right` doesn't do anything. Only once `takeLeft`
// is set to `false`, a dependency on `right` will be created
// (and the dependency on `left` will be removed).
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

Is it theoretically possible to write runWithWatchableValues and get the desired result?
No. Arguments are not passed lazily in JavaScript. You would need to strictly evaluate the functions before passing the values to the wrapped function, and that's what you are trying to avoid.
Is there another automated way (Babel/build steps?) you can think of to prevent having to manually rewrite pick to work with wrapped values?
Sure, you can write your own compiler that does that (it seems relatively easy), but I doubt there is an existing babel plugin that does this. Lazy evaluation is not useful that often, most functions use all their arguments in any case.

You can handle a form of "lazy evaluation" in your pick function, if you can change how data is passed to that function:
function pick(takeLeft, left, right){
if(typeof takeLeft === "function"){
takeLeft = takeLeft();
}
let choice = takeLeft ? left : right;
if(typeof choice === "function"){
choice = choice();
}
return choice;
}
const p1 = pick(
() => true,
() => { console.log("Left is called!"); return "left"; },
() => { console.log("Right is called!"); return "right"; });
const p2 = pick(
false,
"left",
"right");
console.log(01, p2)
As you can see, the 2nd parameter isn't called if you tell it to get the left one, but you can still pass normal variables.
So, if you want something to be evaluated lazily, only if it's chosen, pass it as a callback instead of a normal value.

Related

In JavaScript, how do default function values play with monomorphism

Curious about the scenario where the developer is trying to keep a function monomorphic, but uses default function parameters in JavaScript. So something like
Example A:
const myFunc = (o = {x: 0}) => {
return o.x;
}
And also the situation where the argument being passed is not defaulted to the same shape, something like
Example B :
const myFunc = (o = {}) => {
return o.x;
}
Do either of these example remain monomorphic if the default function parameters are used instead of the correct passed shape? I am curious about the optimization of these scenarios.

Converting function with logic and ui into higher order functions

I'm trying to improve my JavaScript skills. I'm learning composability and functional patterns and I'm totally lost.
I have two functions: one mapping an array and the other called from within the previous function to generate the markup.
const names = ['peter', 'paul', 'patrice']
const namesMarkup = name => {
return `<p>${name}</p>`
}
const showNames = listOfNames => {
return listOfNames.map(el => {
return namesMarkup(el)
})
}
showNames(names)
I have been reading about HOF, which technically are functions that take a function as an argument and/or return a function.
How could I compose these functions to have a HOF?
I went through the basic examples like
const square = num => num * num
const plus10 = (num, callback) => {
return callback(num) + 10
}
console.log(addTwo(7, square))
but I cannot make my mind around the previous example and working with lists.
I will appreciate help since the more I research the more confused I get.
Your mistake is to assume an array for showNames. Never do this. Always implement the simplest version of a function. In FP array is a computational effect. Don't implement such an effectful function as default:
const nameMarkup = name => {
return `<p>${name}</p>`;
}
const nameMarkup2 = name => {
return `<p>${name.toUpperCase()}!</p>`;
}
const showName = f => name => {
const r = f(name);
/* do something useful with r */
return r;
}
const names = ['peter', 'paul', 'patrice']
console.log(
showName(nameMarkup) ("peter"));
// lift the HOF if you want to process a non-deterministic number of names:
console.log(
names.map(showName(nameMarkup2)));
Now swapping the markup just means to pass another function argument. Your showName is more general, because a HOF lets you pass part of the functionality.
If we drop the array requirement, your showNames doesn't do anything useful anymore. It still illustrates the underlying idea, though.

Best approach to avoid multiple check conditions in Javascript

In order to write quality code with good readability, I'm adopting currying functions approach and making pure helper functions for most of the repetitive code snippets. I just observed that I’m having an existence/type check everywhere in my project to avoid any possible errors like type of undefined.
The checks are like:
if (param){
action...
}
I'm thinking to create a global helper function that should take two parameters; param that need to be checked and the action function to perform the action in case the check passes. Something like:
function isExist(param, action){
if (param){
action();
}
}
This functions is not ideally working for all snippets/cases. How can i make it efficient and globally functional for all cases? Also is this the right approach. If not then what is the best approach that i should follow to achieve my aim here?
Example:
if (userInput){
saveToDB(userInput);
}
if (valueFromDB){
performSomeAction();
}
if (username && password){
validate(username, password)
}
I want all of these checks at different points in my code to be replaced by single helper function to somewhat like:
isExist( userInput, saveToDB(userInput) );
isExist( valueFromDB, performSomeAction );
isExist( (username && password), validate(username, password) );
In this way we've replaced this 9 lines of code with just three lines. This is what I wanna achieve.
Well, if you try to think of a good name for
function isExist(param, action){
if (param){
action();
}
}
Then I think one good candidate would be conditionalExecute(condition, codeToExecute). Does this kind of work sound familiar? Are you sure you're not just reinventing the if-statement itself?
Maybe I'm missing your point, but I can't personally see the benefit of encapsulating the logic of the if-statement more than it already is.
Edit: It should be noted that within the context of Javascript the code
if(someVariable){
// do something
}
already reads like "If someVariable is truthy (which undefined is not) then....
But sure, if you only want to check for existance (a variable not being undefined) I won't argue against you if you say it's preferable to have a named function that makes that clear.
In that case I think it's clearer to only encapsulate the actual existence check (or what ever you want to check), not the conditional nature (because for that we already have the if-statement). So something like
function exists(x) {
return x !== undefined; // or something like that
}
function isNotNull(x) {
//TODO:
}
Then your code would become more explicit and readable, and you could combine the functions if you wanted
function neitherUndefinedNorNull(x){
return exists(x) && isNotNull(x);
}
if(neitherUndefinedNorNull(X)){
// your "regular" code here
}
If the code inside of the if-statement is repeated, then extract that as a function as well.
function myRepeatedCode() {
// do stuff
}
function someAlternativeCondition(x){
// test
}
if(neitherUndefinedNorNull ){
myRepeatedCode();
} else if(someAlternativeCondition(x)) {
myRepeatedCode();
}
// OR combine them in the same if-statement
if(neitherUndefinedNorNull(x) || someAlternativeCondition(x)){
myRepeatedCode();
}
Last edit: If you're chasing characters you could even write
// because of short-circuiting, myFunc1 and myFunc2 will only
// execute if myCond1 resp myCond2 is true (or truthy).
myCond1(x) && myFunc1(x)
myCond2(y) && myFunc2(y)
This is the perfect place to use Maybe:
const enumerable = true;
// data Maybe a = Nothing | Just a
const Maybe = {};
const Nothing = Object.create(Maybe);
const Just = value => Object.create(Maybe, {value: {enumerable, value}});
// instance Functor Maybe where
Nothing.map = _ => Nothing;
Maybe.map = function (fun) { return Just(fun(this.value)); };
// instance Applicative Maybe where
Maybe.of = Just;
Nothing.ap = _ => Nothing;
Maybe.ap = function (maybe) { return maybe.map(this.value); };
// instance Monad Maybe where
Nothing.chain = _ => Nothing;
Maybe.chain = function (kleisli) { return kleisli(this.value); };
Maybe follows the Fantasy Land Specification[1]. Using Maybe allows you to write code like this:
// userInput :: Maybe Data
// saveToDB :: Data -> Something
userInput.map(saveToDB); // :: Maybe Something
// valueFromDB :: Maybe Data
// performSomeAction :: Data -> Maybe Something
valueFromDB.chain(performSomeAction); // :: Maybe Something
// username :: Maybe String
// password :: Maybe Password
// validate :: String -> Password -> Something
Maybe.of(validate).ap(username).ap(password); // :: Maybe Something
Anyway, if you're really interested in functional programming then I suggest that you Learn You A Haskell.
[1] I don't agree with the Fantasy Land Specification on flipping the arguments of ap.
how about this, it can process the parameters at same time.
function test(a,b,c)
{
console.log("%s,%s,%s",a,b,c)
}
function check_and_run(param,action){
var args = Array.prototype.slice.call(arguments); //turn arguments to array
args.shift(); //remove param and action
args.shift();
if(param)
action.apply(this,args)
}
check_and_run(1,test,1,2,3) //this will invoke test(1,2,3)
check_and_run(0,test,1,2,3) //this will do nothing
Perhaps something like this:
function conFun(fnCondition, fnCall, defaultResult=undefined) {
return (...rest) => {
if( fnCondition(...rest) ) {
return fnCall(...rest)
}
return defaultResult;
}
}
const add = conFun(
(...rest) => rest.every(n => typeof n === 'number'),
(...rest) => rest.reduce((a, n) => a+n),
NaN);
add("1", "2"); //=> NaN
add(1, 2); //=> 3
So in your question you might be after the first argument not being undefined:
const firstDefined = (v) => typeof v !== 'undefined';
const cSomeFun = conFun(firstDefined, someFun, "");
cSomeFun(); // ==> ""
cSomeFun("test"); // ==> whatever someFun("test") returns
If you are just looking to call something based on non undefined arguments you can simply define it like this:
function callDefined(fn, ...rest) {
if( rest.every(firstDefined) ) {
return fn(...rest)
}
return undefined;
}
callDefined( saveToDB.bind(this, userInput), userInput);
callDefined( performSomeAction, valueFromDB);
callDefined( calidate.bind(this, username, password), username, password);

How to curry a function that takes an options object as argument rather than several distinct arguments?

I have been looking into partial application and currying over the last few days.
I'm wondering how could I use these concepts with a function that only takes one options object as argument.
const myFunc = options => {
const options.option1 = options.option1 || 'default value';
const options.option2 = options.option2 || 'another default value';
// ... etc, it takes about 5 more options, all of which have a
// default fall-back value if not supplied
return doSometing(options);
}
In that case, I don't feel good changing the myFunc signature and pass every option as a separate argument because it's a pain to remember the order in which the options must be supplied.
I'd like to stick with a functional style and avoid instantiating objects with new ... just to keep state; I have a hunch this can be achieved with partial application. It keeps things simpler when it's time for testing, or to instantiate.
But then, I don't know how to do partial application properly without separate arguments.
How would you handle this refactor?
I would suggest that the equivalent of currying a function taking an option object would be the same as how to handle defaults. Consider this as a partial applier:
myFuncWithMyOptions(myFunc, myOptions) {
return function(options) {
return myFunc(Object.assign({}, myOptions, options));
}
}
If you want the options in myOptions not be be overridden by those in options simply swap the two arguments to Object.assign
Following on Dan D's answer and the comments, this technique would let you partially apply such a function repeatedly until all the required fields are supplied:
const vals = (obj) => Object.keys(obj).map(key => obj[key]);
const addDefaults = (() => {
const req = Symbol();
const addDefaults = (defaults, fn) => (options) => {
const params = Object.assign({}, defaults, options);
return (vals(params).includes(req))
? addDefaults(params, fn)
: fn(params);
};
addDefaults.REQUIRED = req;
return addDefaults;
})();
const order = addDefaults({
color: addDefaults.REQUIRED,
size: addDefaults.REQUIRED,
giftWrap: false,
priority: false
}, (opts) =>
`${opts.size}, ${opts.color}, ${opts.giftWrap ? '' : 'no'} wrap, priority: ${opts.priority}`
);
order({color: 'Red', size: 'Medium'}); // "Medium, Red, no wrap, priority: false"
const orderLarge = order({size: 'Large'}); // Options -> String
orderLarge({color: 'Blue'}); // "Large, Blue, no wrap, priority: false"
I don't think your problem is connected with partial application. What exactly does myFunc do actually?
it sets a couple of optional default values
it invokes another function
This is not much. And yet two problems arise:
the function composition is hard coded and hidden in the body of myFunc
it doesn't get apparent from the function signature which default values are overwritten
Simply put, a "proper" function reveals its functionality by its signature. So let's get rid of the myFunc wrapper:
const options = {
foo: 1,
bar: true,
bat: "",
baz: []
};
// function composition
const comp = (...fs) => x => fs.reduceRight((acc, f) => f(acc), x);
// applicator for partial application with right section
const _$ = (f, y) => x => f(x) (y); // right section
// `Object` assignment
const assign = o => p => Object.assign({}, o, p);
// specific function of your domain
const doSomething = o => (console.log(o), o);
// and run (from right-to-left)
comp(doSomething, _$(assign, {baz: [1, 2, 3], bat: "abc"})) (options);
Now you can exactly see what is going on without having to look into the function bodies. The property order of the options Object doesn't matter either.
A remark on _$. It has this odd name because I prefer a visual name over a textual one in this particular case. Given the function sub = x => y => x - y, _$(sub, 2) simply means x => x - 2. This is called the right section of the partially applied sub function, because the "left" argument is still missing.

Use of Either and returning the error immediately

I have a function which returns an instance of Either where the Left side represent the exception / error, while the second side stores the return value.
If the Either instance has been Left instantiated to the Error branch I want to return immediately. If the instance has been Right instantiated I want to wrap that in a Maybe and continue on (as it comes into the function as a Maybe, and only gets looked up if it is Nothing).
This is working per my test cases:
isNothing being passed in :: lookup is in error
isNothing being passed in :: lookup is successful
isJust(22) being passed in (lookup doesn't execute)
The code feels OK, but I don't supect I may be missing sme of the finer points of the Folktale data.either library.
// from data.monad
const someValue = Maybe.Nothing()
// ...snip...
if (someValue.isNothing) {
// from data.either :: Either.Left | Either.Right
const possiblySomeValue = yield lookupSomeValue()
if(possiblySomeValue.isLeft) {
return possiblySomeValue
} else {
someValue = Maybe.Just(possiblySomeValue.get())
}
}
I am combining ES6 (Node 4.1) with Folktale: data.either and data.maybe. My goal is really elevating my understanding in how to write properly in this style
update the problem is a little more complex I ahve back to back independent lookups, which I feel could be chained together:
// from data.monad
const someValue = Maybe.Nothing()
// ...snip...
if (someValue.isNothing) {
// from data.either :: Either.Left | Either.Right
const possiblySomeValue = yield lookupSomeValue()
if(possiblySomeValue.isLeft) {
return possiblySomeValue
} else {
someValue = Maybe.Just(possiblySomeValue.get())
}
}
// from data.monad
const someValue2 = Maybe.Nothing()
// ...snip...
if (someValue2.isNothing) {
// from data.either :: Either.Left | Either.Right
const possiblySomeValue2 = yield lookupSomeValue2()
if(possiblySomeValue2.isLeft) {
return possiblySomeValue2
} else {
someValue2 = Maybe.Just(possiblySomeValue2.get())
}
}
Its the back to back occurances whcih make the code super ugly...
This is the current state of my code which I think is better. First be able to convert the Maybe to an either, to allow me to chain / orElse with transformations (Maybe.orElse does not allow take a function, whereas the Either.orElse does take a function for the transformation)
const maybeToEither = function(maybe) {
if (maybe.isNothing) {
return Either.Left(undefined)
} else {
return Either.Right(maybe.get())
}
}
then, since I ma unpackaging the Maybe.Just into the Either.Right as part of the conversion, I simply need to provide the orElse transformation.
const someValue = maybeToEither(maybeSomeValue).orElse(function(ignore){
return lookupSumValue()
}).get()
Blending into my actual problem, with generators lead to a slightly ugglier solution. lookupSomeValue is a generator function, so we need to yield. Also since the value is used in multiple places we want to force this into a value with get.
const someValue = (yield maybeToEither(maybeSomeValue).orElse(function(ignore){
return lookupSumValue()
})).get()
so when repeated the code isn't nearly as bad as my original solution -
const someValue = (yield maybeToEither(maybeSomeValue).orElse(function(ignore){
return lookupSumValue()
})).get()
const someValue2 = (yield maybeToEither(maybeSomeValue2).orElse(function(ignore){
const someRandom = getRandom()
return lookupSumValue2(someRandom)
})).get()
I am still looking for a more concise grammar. Will update with another solution if I find one.
Maybe (pun fully intended) a better approach
const someValue = (yield maybeToEither(maybeSomeValue).cata({
Left: lookupSumValue,
Right: yieldableRight})).get()
with these two helper functions
const yieldableRight = function(value){
return function*(){ return Either.Right(value) }
}
const maybeToEither = function(maybe) {
if (maybe.isNothing) {
return Either.Left(undefined)
} else {
return Either.Right(maybe.get())
}
}
Where lookupSomeValue is in the form (a function that returns a Generator):
const lookupSomeValue = function(){
return ((function *(){
return 10
})())
}
The problem is that the Right side needs to return something that is yieldable. For some reason Koa/Co is choking on the Either.Right() (even though Objects are yieldable), as a yieldable - so I return a generator that returns the value. I get that (I don't understadn whay I can't yield on the Either.Right, but thats a different problem).
I don't understand why the Right side needs to be wrapped back up in an Either, while the Left side doesn't.

Categories

Resources