How can I pipe functions in JS like Elm does? - javascript

I'm just getting into functional programming and i'm having a hard time figuring out how to do this (if it's even worth the trouble). I've looked into currying and am not sure if this is the direction I need to go?? Or pipelines?
I would like to start with a value and then pipe it through different functions. Underscore has the 'chain' method which is similar. However I don't want to use prototypes to do this. I realize the solution might not match my target syntax.
Elm has the |> syntax (below) which is really nice to look at
// what i'd like to do (or similar) in JS *without using prototype*
num = ("(123) 456-7890")
.removeDashes()
.removeParens()
.removeSpaces()
// what elm does
"(123) 456-7890"
|> removeDashes
|> removeParens
|> rem
// functions I wrote so far
removeDashes = function(str) {
return str.replace(/-/g, '');
};
removeParens = function(str) {
return str.replace(/\(|\)/g, '');
};
removeSpaces = function(str) {
return str.replace(/\s/g, '');
};
// what i'm currently doing
num =
removeDashes(
removeParens(
removeSpaces(
"(123) 456-7890"")));

If you want to get you're feet wet with functional programming in JavaScript I'd advice you to use a library like Underscore, Lodash or Ramda. Which all have a compose/pipe functionality. Most of the times you'd want to combine it with some form of partial application which those libraries also provide.
Anyway it's a nice exercise to try to implement it yourself.
I would solve it like this...
/* Asumes es5 or higher */
function pipe (firstFn /* ...restFns */) {
var _ = null;
var _slice = Array.prototype.slice;
var restFns = _slice.call(arguments, 1) || [];
return function exec_fns() {
var args = _slice.call(arguments, 0, 1);
return restFns.reduce(function(acc, fn) {
return fn.call(_, acc);
}, firstFn.apply(_, args));
}
}
removeDashes = function(str) {
return str.replace(/-/g, '');
};
removeParens = function(str) {
return str.replace(/\(|\)/g, '');
};
removeSpaces = function(str) {
return str.replace(/\s/g, '');
};
console.log(pipe(
removeDashes,
removeParens,
removeSpaces
)("(123) 456-7890") == "1234567890")
Also Functional JavaScript by Fogus is a nice resource to dig deeper into this style of programming

There are different ways to tackle this problem, and you've offered references in underscore and Elm.
In Elm, curried functions are an important part of the equation. As every function receives a single argument, you can build chains with some of them partially applied, waiting for the argument you're weaving in with the pipeline. The same applies to Haskell, PureScript and languages of their ilk.
Reproducing that ipsis literis in JavaScript requires a little bit of sugar — you can use a sweet.js macro to get a source transformation that does it.
Without sugar, it can go many ways. Maybe one way to explore is using generators, passing the bits of the resolved chain down until you get a non-function value.

Like hindmost said, look into using prototypes. The string prototype allows you to add class-level functionality to all strings:
String.prototype.removeParens = function() {
this = this.replace(/\(|\)/g, '');
}
This lets you do things like this:
var myString = "(test)";
myString.removeParens();
And once you add the other functions to the String prototype you can simply chain the function calls like this:
myString.removeDashes().removeParens().removeSpaces();
etc.

You can create the pipe function in one line, with good readability:
const pipe = (...fns) => fns.reduce((v, f) => v.constructor === Function ? v() : f(v));
and it would be used in this way:
var numResult = pipe('(123) 456-7890', removeDashes, removeParens, removeSpaces);
var pipe = (...fns) => fns.reduce((v, f) => v.constructor === Function ? v() : f(v));
function removeDashes(str) {
return str.replace(/-/g, '');
}
function removeParens(str) {
return str.replace(/\(|\)/g, '');
}
function removeSpaces(str) {
return str.replace(/\s/g, '');
}
console.log(
'result:', pipe('(123) 456-7890', removeDashes, removeParens, removeSpaces)
);
Attention: this function needs a platform with support for the spread operator ....
Just in case, i've created a module for this with support for async functions (Promises) and it also works on older/legacy platforms that can't use the spread ...
https://github.com/DiegoZoracKy/pipe-functions

The easiest way is to really just add those to the prototype chain, but you can do that with an object. Here's an easy example:
function MyString( str ){
var value = str.toString();
return {
removeDashes: function() {
value = value.replace(/-/g, '');
return this;
},
removeParens: function() {
value = value.replace(/\(|\)/g, '');
return this;
},
removeSpaces: function() {
value = value.replace(/\s/g, '');
return this;
},
toString: function (){
return value;
},
valueOf: function (){
return value;
}
};
}
You can later on do this:
var clean = (new MyString('This \\(Is)\/ Dirty'))
.removeDashes()
.removeParens()
.removeSpaces();
This way, you will keep your prototype clean. To retrieve a non-object value, just run the toStrong() method, toValue() or do anything with the value (contatenating 1, divide it, anything!).

Here's a solution I found with lodash, it allows you to mixin your own functions and then use them against chain:
...
removeSpaces = function(str) {
return str.replace(/\s/g, '');
};
_.mixin({
removeSpaces: removeSpaces,
removeParens: removeParens,
removeDashes: removeDashes
});
num = _.chain("(123) 456-7890")
.removeSpaces()
.removeParens()
.removeDashes()
.value()

Not a very serious suggestions, but one that will work:
var update = pipe()(removeDashes >> removeParens >> removeSpaces);
update("(123) 456-7890"); //=> "1234567890"
This is based upon this implementation of pipe:
var pipe = function() {
var queue = [];
var valueOf = Function.prototype.valueOf;
Function.prototype.valueOf = function() {
queue.push(this);
return 1;
};
return function() {
Function.prototype.valueOf = valueOf;
return function(x) {
for (var i = 0, val = x, len = queue.length; i < len; i++) {
val = queue[i](val);
}
return val;
}
};
};
You can see more in slide 33 of my talk on functional composition in js.

As the others have said, adding the functions to the String prototype is a valid and short solution. However, if you don´t want to add them to String prototype or if you want to perform in the future more complex functions, another option is to make a wrapper to handle this:
function SpecialString(str){
this.str = str;
this.removeDashes = function() {
this.str=this.str.replace(/-/g, '');
return this;
};
this.removeParens = function() {
this.str=this.str.replace(/\(|\)/g, '');
return this;
};
this.removeSpaces = function() {
this.str=this.str.replace(/\s/g, '');
return this;
};
return this;
}
num = new SpecialString("(123) 456-7890").removeDashes().removeParens().removeSpaces();
console.log(num) // 1234567890

Related

How do I make 'foo()' and 'foo().bar()' output completely different things?

So I'm trying to make it so foo() returns anything from a string to object, then have foo().bar() return something completely different and even have foo().bar().test() return another thing completely different. For example, databases() would return something like a list of databases, then databases().users() would return an object of all the users and finally databases().users().ids() would return an array of IDs.
I think it's called function/method chaining but I haven't found anything related to what I need.
All I find is examples like var number = new math(10) number.add(5).subtract(3).value but I don't want it to chain it like that, I want it very linear (I don't know how to explain). I don't want to be able to use number.subtract(3).add(5).value or databases().ids().users() and I don't want to have to have .value at the end.
var math = function (n) {
this.value = n;
this.add = function (x) {
this.value += x;
return this;
};
this.subtract = function (x) {
this.value -= x;
return this;
};
};
var number = new math(10);
console.log(number.add(5).subtract(3).value);
The node js module, moment, works the way I'd like my project to work. moment() returns Moment<...>, moment().hours() returns the hour and moment().format("YYYY/MM/DD") returns 2020/10/22.
You can do something like this if you want number capacity and limited string capacity:
class Database extends String {
valueOf() { return 2 }
users() { return { ids: () => [] } }
};
const database = (val) => new Database(val || "")
Then you will be able to do this database() + 2 === 4, all string methods will be available and you will be able to do this database().users().ids()

functional composition javascript

I'm trying to understand functional composition in Javascript and followed a talk which describes the compose function
I tried the following program which will accept a sentence, break it up into pieces (delimited by space) and use uppercase on each word and return an array of words.
function compose(f, g) {
"use strict";
return function() {
return f.call(this, g.apply(this,arguments));
}
}
var split = function (string, delim) {
"use strict";
return string.split(delim);
};
var uppercase = function (string) {
"use strict";
if (string instanceof Array) {
return string.map(function (x) {
return x.toString().toUpperCase();
});
} else {
return string.toString().toUpperCase();
}
//return string.toString().toUpperCase();
};
var myfunc = compose(uppercase,split);
var data = myfunc("Elementary! My dear Watson",/\s+/);
console.log(data);
Though I got what I wanted, but the code is ugly on following counts:
I've to re-define split and toUpperCase as I constantly got
"Reference error: toUpperCase not defined". Is it because they are
methods and not pure functions per se?
the uppercase method is ugly because it should receive just a single string so that it flips the case,but since I'm tokenizing it, this function receives an array and hence the ugly array check.
How can the code be improvised to have a "pipe of functions" viz. split -> map -> uppercase ?
Here is the same sort of code that you have which has been simplified a little. If this is the direction you want to take with your coding I cant recommend Javascript Allonge by Reg Braithwait enough, It completely changed the way I thought about writing code.
Hopefully this small example shows how to compose functions and how useful functional js is. Another big benefit is that if you are using pure functions that don't look to the outer scope you can easily debug issues as there is a dependable stream of function calls that you can follow.
Learning Functional enough to be able to understand it's basic concepts took me about 6 months and constant practice. but it was well worth the effort.
"use strict"; // you just need one use strict on the hholee file
// for compose you shouldn't really need to call or apply as this is always the window for a pure function
function compose(a, b) {
return function( c ) {
return a( b( c ) );
}
}
// split is now a simple function that takes a delimeter and returns a function that splits the string
function split(delim) {
return function( string ){
return string.split(delim);
}
};
// if you add a function mapper you can remove some of the complexity in uppercase
// and compose map with uppercase
function map( fn ){
return function( arr ){
return Array.prototype.map.call( arr, fn );
}
}
// this is now a very simple single responsibility function that can be composed
function uppercase(string) {
return string.toUpperCase();
};
var
splitBySpace = split(/\s+/),
arrToUpper = map(uppercase),
myfunc = compose(arrToUpper,splitBySpace);
console.log( arrToUpper(['one', 'two']) );
console.log( myfunc("Elementary! My dear Watson") );
// if you want to split on a different character you will need to create a new split function by currying a different delimeter
var
splitByChar = split(''),
splitByBang = split('!');
// you also don't have to compose the functions you can write them out normally but it is much harder to follow eg.
console.log( map(uppercase)(split('')("Elementary! My dear Watson") ) );
<script src="http://codepen.io/synthet1c/pen/WrQapG.js"></script>
Here is a small example of how to get a fluent interface up and running covering the third part of your question. the key thing to take away is you create an object with new Obj and in the methods you need to return this to allow method chaining.
Functional Javascript cannot allow chaining methods as it has no internal state, you use functional js to decorate and mix other functions that can return either a value or another function.
// MyObj is declared within a module to make the internals private
var myObj = (function() {
// Constructor function
function MyObj(string, delim) {
this.input = string;
this.delim = delim;
}
// create the MyObj methods on it's prototype
// all methods have been decorated with the fluent function
MyObj.prototype = {
// split the input
split: fluent(function(delim) {
if( ! Array.isArray( this.input ) ){
this.input = this.input.split( delim != null ? delim : this.delim);
}
}),
// convert the text to uppercase
uppercase: fluent(function() {
if (Array.isArray(this.input)) {
this.input = this.input.map(function(string) {
return string.toUpperCase();
});
} else {
this.input = this.input.toUpperCase();
}
}),
// reverse the array
reverse: fluent(function(){
if( Array.isArray( this.input ) ){
this.input = this.input.reverse();
}
else {
this.input = this.input.split('').reverse().join('');
}
}),
// you will need a getter if you are using a fluent interface or decide what your end points will be
get: function() {
return this.input;
}
}
return function constructor(string, delim) {
return new MyObj(string, delim);
}
})();
// myObj is the function to create a MyObj
console.log( myObj );
console.log( myObj("Elementary! My dear Watson", /\s+/ ).split().uppercase().get() );
// with the code you can override the default delimeter
console.log( myObj("Elementary! My dear Watson", /\s+/ ).split('').uppercase().get() );
// run different methods
console.log( myObj("Elementary! My dear Watson", /\s+/ ).split().uppercase().reverse().get() );
// order no longer matters
console.log( myObj("Elementary! My dear Watson", /\s+/ ).reverse().uppercase().split().get() );
// MyObj also has an internal state so you can do
// functional decorator - this will make the prototype methods return a value or this
function fluent(method) {
return function() {
var ret = method.apply(this, arguments);
return ret != null
? ret
: this;
}
}
<script src="http://codepen.io/synthet1c/pen/WrQapG.js"></script>
Functional composition is just when you take two or more functions, and make one a single function out of them. I've written up a pretty easy to follow explanation of composing functions that I think will clear up quite a few things for you.
What you want however is something very different, and is very straight forward in javascript
"Elementary! My dear Watson".split(/\s+/).map(val => val.toUpperCase());
or if you really want it as a function like you have above...
function myFunct(str, delim) {
str.split(delim).map(val => val.toUpperCase());
}
composing function allows reusability of functions. You can apply javascript reduce method to apply set of functions on data.
Lets start with a basic reduce sample. The following is set of functions to calculate sale price.
const SALES_TAX = 0.08;
const COUPON_CODES = {
AAAA: 0.1,
BBBB: 0.07,
CCCC: 0.15,
};
const shoppingtotal = shoppingCart =>
shoppingCart.reduce((acc, item) => {
acc += item.price * item.qty;
return acc;
}, 0);
const discount = couponCode => amount =>
amount * (1 - COUPON_CODES[couponCode]);
const tax = amt => amt * (1 + SALES_TAX);
I can create a compose as below
const compose = fns => input => fns.reduce((acc, fn) => fn(acc), input);
const calculatePayment = compose([shoppingtotal, discount('AAAA'), tax]);
Now to calculate price, I can call calculatePayment.
calculatePayment([
{
name: 'pencil',
price: 1,
qty: 2,
},
{
name: 'Pen',
price: 1.5,
qty: 20,
},
{
name: 'Eraser',
price: 0.25,
qty: 10,
}])
It is a sample. Like this, you can easily compose multiple functions and create new function definitions.

How to build a namespace-like string using chained variables

This is a strange one, but I'm exploring it to see if it's possible.
Let's say that I have a .NET application where I am using PubSub. I want a way to define the topic string using chained objects (not functions). The goal is to allow me a way of defining strings that lets me to take advantage of Visual Studio's IntelliSense and reduce the likelihood of spelling errors.
Here's an example:
/* Manual way */
var topic = "App.Navigation.CurrentItem"
/* Desired Solution */
// ... define the objects here ...
var topic = App.Navigation.CurrentItem;
console.log(topic); // "App.Navigation.CurrentItem"
var topic2 = App.Footer.CurrentItem;
console.log(topic2); // "App.Footer.CurrentItem"
I'd like each object to be responsible for outputing it's own value, and have the chaining process responsible for joining itself to the previous chained object via a predefined separator (in my case, a period [.]).
I've been playing with JavaScript getter syntax, but I'm curious if there's a better way.
Has anyone done something like this before, and if so, how did you solve it?
You're requirements aren't totally clear to me, but are you looking for something like this?
function namespace(ns) { this._ns = ns; }
namespace.prototype.toString = function() {return this._ns};
namespace.prototype.extend = function(suffix) {
return new namespace(this._ns + "." + suffix)
};
Usage:
App = new namespace('App');
App.Navigation = App.extend('Navigation');
App.Navigation.CurrentItem = App.Navigation.extend('CurrentItem');
console.log(App.Navigation.CurrentItem.toString()); // "App.Navigation.CurrentItem"
This is what I ended up with after reviewing StriplingWarrior's answer:
function Namespace(name, config) {
if (typeof name === "object") {
config = name;
name = null;
}
config = config || {};
this._ns = name;
this.define(config);
}
Namespace.prototype.toString = function() { return this._ns };
Namespace.prototype.define = function(config, base) {
base = base || this;
for (key in config) {
var name = (base._ns) ? base._ns + "." + key : key;
base[key] = new Namespace(name);
base.define(config[key], base[key]);
}
return base;
};
Usage:
var App = new Namespace("App", {
Navigation: {
Items: {
Current: {}
}
},
Content: {},
Footer: {
Items: {
Current: {}
}
}
});
console.log(App.toString()); // App
console.log(App.Navigation.Items.Current.toString()); // App.Navigation.Items.Current
console.log(App.Footer.toString()); // App.Footer
I also wrote a convenience method to reduce the toString():
function NS(namespace) {
return namespace.toString();
}
console.log(NS(App.Navigation.Items.Current));
Thanks again to StriplingWarrior for the the help!

Function composition in JavaScript

What's the benefit of function composition implementation in libs like underscore, lo-dash and others, similar to this one:
var compose = function() {
var funcs = arguments;
return function() {
var args = arguments;
for (var i = funcs.length; i --> 0;) {
args = [funcs[i].apply(this, args)];
}
return args[0];
}
};
var c = compose(trim, capitalize);
in comparison to this:
var c = function (x) { return capitalize(trim(x)); };
The latter is much more performant.
For one, it's easier to read. Performance is rarely more important than that. Also, you could make a dedicated arity 2 function with nearly the same performance.
The other benefit is the composition can be easily changed at runtime. You can create versions that trim before capitalization, capitalize before trimming, trim only, capitalize only, or neither, without having to explicitly specify every single combination in the code. This can greatly simplify your code sometimes. Runtime composition is one of those things you never knew you always wanted.
For example:
var c = function(x) {return x;} // identity
var onTrimClick = function() {c = compose(c, trim);}
var onCapitalizeClick = function() {c = compose(c, capitalize);}
var onSomethingElseClick = function() {c = compose(c, somethingElse);}
This lets you create a composed function c at runtime based on what the user clicks and in what order.
//A simple way to understand javascript function composition =>
function composition(...fun) {
return function (value) {
var functionList = fun.slice();
while (functionList.length > 0) {
value = functionList.pop()(value);
}
return value;
}
}
function mult2(value) {
return value * 2;
}
function mult3(value) {
return value * 3;
}
function mult5(value) {
return value * 5;
}
var composedFun = composition(mult2, mult3, mult5);
console.log(composedFun);
console.log(composedFun(1));
console.log(composedFun(2));

Stringify function in JavaScript

What I am thinking of writing is something like this.
Object.prototype.toString = function(){
var ret = '{';
for(var i in this){
if(this[i].toString)
ret = ret + ( '"'+i+'":' + this[i].toString())
}
ret=ret+'}'; return ret;
}
I will do this for Number and other known dataTypes.
I have seen many utils.stringify fucntions available , along with JSON.stringify, what all these libs are doing is that, they are checking type of object and based on that they concatenating strings to create Json. which is ok, I cant use those fucntions because I want to use something like this: -
function subMap(){
this.data = { a : 'A', b : 'B'}
this.toString = function(){
return this.data.toString()
}
}
utils.parse(({
x : new subMap()
}).toString())
which should return something like this
"{"x":{"a":"A","b":"B"}}"
Basically I want to have way where I can decide how to represent StringFormat(JSON) for any ObjectType, whenever I add a new DataType.
But looking at all the available libs I see no one is doing this way(defining toString function), which i m thinking is better way. Is there any drawback or something JavaScript is using it internally to do something which will break something or any other reason they are not using it?
Edit
I found the answer. at link
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
function subMap(){
this.data = { a : 'A', b : 'B'}
this.toJSON = function(){
return this.data;
}
}
should work as I expect.
You can use the second argument to JSON.stringify(value, replacer, space) to do this: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
Try using toJSON
function subMap(){
this.data = { a : 'A', b : 'B'}
this.toJSON = function(){
return this.data;
}
}
this may solve your problem

Categories