Ok, I have another answer here, and I think this is a fairly innovative approach.
Basically, the problem with doing something similar to Naomik's answer is that you create functions every time you combine methods together.
EDIT: This solution has the same problem, however this answer remains for educational purposes.
So here, I suggest simply binding the new values ββto your methods - which are basically just independent functions. This gives an additional advantage - the ability to import functions from different modules into a new object.
Okay, thatβs all.
const assoc = (prop, value, obj) => Object.assign({},obj,{[prop]: value}) const reducer = ( $values, accumulate, [key,val] ) => assoc( key, val.bind( undefined,...$values ), accumulate ) const bindValuesToMethods = ( $methods, ...$values ) => Object.entries( $methods ).reduce( reducer.bind( undefined, ...$values), {} ) const prepareInstance = (instanceMethods, staticMethods = ({}) ) => Object.assign( bindValuesToMethods.bind( undefined, instanceMethods ), staticMethods )
Now you can do
Right(4) .map(x=>x+1) .map(x=>x*2) .inspect()
You can also do
Right.of(4) .map(x=>x+1) .map(x=>x*2) .inspect()
You also have the added benefit of being able to export from modules as such.
export const Right = prepareInstance(RightInstanceMethods,RightStaticMethods)
Until you get ClassInstance.constructor , you have FunctorInstance.name (note that you may need polyfill Function.name and / or not use the arrow function to export for browser compatibility with Function.name )
export function Right(...args){ return prepareInstance(RightInstanceMethods,RightStaticMethods)(...args) }
PS - New name suggestions for prepareInstance are welcome, see Gist.
https://gist.github.com/babakness/56da19ba85e0eaa43ae5577bc0064456