Spices
Consider modifying your function so that instead of accepting two arguments, it only takes one argument and then returns a second function that accepts the second argument. This technique is commonly referred to as spices.
// flavorValidator :: number -> string -> boolean
const flavorValidator = (limit: number) => (taste: string): boolean => {
if (taste.length > limit) return false;
return true;
};
// ... later ...
seasoning: flavorValidator(255);
This approach allows you to create various validators by calling the function: flavorValidator(10)
will provide you with a validator for limiting taste to 10 characters. And since it's a function, you can also assign it to a variable:
//sauceTasteValidator :: string -> boolean
const sauceTasteValidator: (taste: string) => boolean = flavorValidator(10);
Switch parameters for partial allocation
Rather than receiving value first followed by max length, receive the length initially. It achieves the same outcome as currying but retains the option to accept two parameters:
const flavorValidator = (limit: number, taste: string): boolean => {
if (taste.length > limit) return false;
return true;
};
// ... later ...
seasoning: flavorValidator.bind(this, 255);
The concept is similar. However, this method offers more versatility - you can either call the function with both parameters flavorValidator(10, food)
or apply it partially with just one parameter. The latter results in essentially the same outcome as currying, as it generates a new function with the same signature:
//sauceTasteValidator :: string -> boolean
const sauceTasteValidator: (taste: string) => boolean = flavorValidator.bind(this, 10);
Despite the resemblances, spices are not equivalent to partial application. Additionally, it's feasible to curry a function of any arity (number of parameters) to enable processing of individual or multiple parameters at once. For instance, refer to _.curry
in Lodash
function add4(a, b, c, d) {
console.log(a + b + c + d);
}
const spiceAdd4 = _.curry(add4);
spiceAdd4(1)(2)(3)(4);
spiceAdd4(1, 2, 3, 4);
spiceAdd4(1)(2, 3)(4);
spiceAdd4(1, 2, 3)(4);
spiceAdd4(1)(2, 3, 4);
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5f33303031373018147b6e7d60776c79764b4a497535494"><strong>[email protected]</strong></a>/lodash.min.js"></script>
Partial application using a placeholder or from the right
You can maintain the current format and adjust partial applications. While Function#bind
lacks flexibility, you can craft your own solution or opt for a library. Let's utilize Lodash again, which offers solid implementations for these cases:
Using a placeholder for partial application
This method enables skipping certain parameters when applying partially. Thus, you can skip the initial parameter and solely set the second one:
const flavorValidator = (taste, limit) => {
if (taste.length > limit) return false;
return true;
};
//sauceTasteValidator :: string -> boolean
const sauceTasteValidator = _.partial(flavorValidator, _, 10);
console.log(sauceTasteValidator("seasoningTooStrong"));
console.log(sauceTasteValidator("subtleFlavor"));
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="330f12110002110538060d01080d09">[email protected]</a>/lodash.min.js"></script>
Right-to-left partial application
Apply partial functions starting from the right side towards the left, initiating with setting limit
:
const flavorValidator = (taste, limit) => {
if (taste.length > limit) return false;
return true;
};
//sauceTasteValidator :: string -> boolean
const sauceTasteValidator = _.partialRight(flavorValidator, 10);
console.log(sauceTasteValidator("seasoningTooStrong"));
console.log(sauceTasteValidator("subtleFlavor"));
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="68040704051920061c060013131614051204">[email protected]</a>/lodash.min.js"></script>