I notice that scan is missing from the various transducer libraries that I looked at (e.g transducers-js). Is it impossible to implement or am I missing something?
Actually I can answer my own question. I was trying to implement it in a functional way and I misunderstood how the transducer interface is used. Looking at the source code from transducers-js, they generally keep state in an object and I can implement scan the same way:
var Scan = function( agg, start, xf ){
this.xf = xf;
this.agg = agg;
this.accum = start;
}
Scan.prototype.init = function(){
return this.xf.init();
}
Scan.prototype.result = function(v) {
return this.xf.result(v);
}
Scan.prototype.step = function( result, input ) {
this.accum = this.agg( this.accum, input );
return this.xf.step( result, this.accum );
}
var scan = function(agg, start) {
return function (xf) {
return new Scan(agg, start, xf);
}
}
Related
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()
I want to use Proxy on a customized class called ObservableList which contains an Array. Since Proxy is available only after ES6, I wonder if there is any alternative implementation.
My requirement is to get updated (rather than get noticed) for observers once ObservableList changes, so that the observers are always consist with observable with some filtering or mapping method.
var activities = new ObservableList(['reading', 'swimming']);
var sAct = activities.filter(function(v) {
return v[0] === 's';
});
// expect sAct.list to be ['swimming']
var meAct = activities.map(function(v) {
return 'I am ' + v;
});
// expect meAct.list to be ['I am reading', 'I am swimming']
activities.list.push('smiling');
console.log(sAct.list, meAct.list);
// expect sAct.list to be ['swimming', 'smiling']
// expect meAct.list to be ['I am reading', 'I am swimming', 'I am smiling']
activities.list[1] = 'snoopying';
console.log(sAct.list, meAct.list);
// expect sAct.list to be ['swimming', 'snoopying']
// expect meAct.list to be ['I am reading', 'I am snoopying', 'I am smiling']
My implementation with Proxy is available at https://jsfiddle.net/ovilia/tLmbptr0/3/
used defineProperty.
not exactly with what you want. i just implemented a "reactive array". but i think it maybe works in your problems.
bad parts:
defined tons of getters/setters on the target.
accessing indexers not defined will be not reactive.
update() is to-be optimized.
good parts:
ES5 friendly.
if no indexers needed, use set(i, val)/get(i) will be reactive.
https://jsfiddle.net/jimnox/jrtq40p7/2/
As described in questions, I only need ObservableList to contain an Array, rather than to extend it, as Jim did in his complicated answer. And surprisingly enough, I found this could be easily achieved by wrapping the original Array operations.
One limitation is that index operation is not reactive in my implementation, in that I failed to find a proper way to capture index operations. If you have a better idea, feel welcomed to tell me! XD
Here's the full implementation.
export class ObservableList {
list: Array<any>;
private _observer: Array<ObserverList>;
constructor(list?: Array<any>) {
this.list = list || [];
this._initList();
this._initMethods();
this._observer = [];
}
notify(): void {
for (let o of this._observer) {
o.update();
}
}
private _initList(): void {
var that = this;
var operations = ['push', 'pop', 'shift', 'unshift', 'splice',
'sort', 'reverse'];
for (let operation of operations) {
this.list[operation] = function() {
var res = Array.prototype[operation].apply(that.list, arguments);
that.notify();
return res;
}
}
}
private _initMethods(): void {
var that = this;
var methods = ['filter', 'map'];
for (let method of methods) {
this[method] = (formatter: Function): ObserverList => {
var observer = new ObserverList(that, formatter, method);
this._observer.push(observer);
return observer;
}
}
}
}
export class ObserverList {
public list: Array<any>;
constructor(public observable: ObservableList,
public formatter: Function,
public method: string) {
this.list = [];
this.update();
}
update(): void {
var list = [];
var master = this.observable.list;
for (var i = 0, len = master.length; i < len; ++i) {
if (this.method === 'filter') {
if (this.formatter(master[i])) {
list.push(master[i]);
}
} else if (this.method === 'map') {
list.push(this.formatter(master[i]));
} else {
console.error('Illegal method ' + this.method + '.');
}
}
this.list = list;
}
}
Is using proxies a hard requirement? I wouldn't recommend proxies for
general programming tasks as you can end up with unpredictable and
hard-to-spot side effects.
If you keep to data and functions to transform it, avoiding mutable
state where possible, I think you'll end up with simpler code that's
easier to maintain.
var activities = ['reading', 'swimming'];
var sfilter = function(activities){
return activities.filter(function(v){
return v[0] === 's';
});
};
console.log(sfilter(activities));
var memap = function(activities){
return activities.map(function(v){
return 'I am ' + v;
});
};
console.log(memap(activities));
activities.push('smiling');
console.log(sfilter(activities));
console.log(memap(activities));
// Yes, I know this doesn't work in quite the same way,
// but you're asking for trouble here since in your
// code you're appending to one list, but overwriting
// an element in the other.
activities[1] = 'snoopying';
console.log(sfilter(activities));
console.log(memap(activities));
Stick to a Single Source of Truth and observe that. With each copy you are multiplying state complexity. That will make debugging, testing, and extending the code difficult.
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.
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!
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