Is it possible to define my own infix function/operator in CoffeeScript (or in pure JavaScript)? e.g. I want to call
a foo b
or
a `foo` b
instead of
a.foo b
or, when foo is global function,
foo a, b
Is there any way to do this?
Is it possible to define my own infix function/operator in CoffeeScript (or in pure JavaScript)? e.g. I want to call
a foo b
or
a `foo` b
instead of
a.foo b
or, when foo is global function,
foo a, b
Is there any way to do this?
ES6 enables a very Haskell/Lambda calculus way of doing things.
Given a multiplication function:
const multiply = a => b => (a * b)
You can define a doubling function using partial application (you leave out one parameter):
const double = multiply (2)
And you can compose the double function with itself, creating a quadruple function:
const compose = (f, g) => x => f(g(x))
const quadruple = compose (double, double)
But indeed, what if you would prefer an infix notation? As Steve Ladavich noted, you do need to extend a prototype.
But I think it can be done a bit more elegant using array notation instead of dot notation.
Lets use the official symbol for function composition "∘":
Function.prototype['∘'] = function(f){
return x => this(f(x))
}
const multiply = a => b => (a * b)
const double = multiply (2)
const doublethreetimes = (double) ['∘'] (double) ['∘'] (double)
console.log(doublethreetimes(3));
['∘']
. This is a great hack! +1 –
Fulgurite Actually adding this as an answer: no, this is not possible.
You can with sweet.js. See:
Sweet.js extends Javascript with macros.
It acts like a preprocessor.
This is definitely not infix notation but it's kinda close : /
let plus = function(a,b){return a+b};
let a = 3;
let b = 5;
let c = a._(plus).b // 8
I don't think anyone would actually want to use this "notation" since it's pretty ugly, but I think there are probably some tweaks that can be made to make it look different or nicer (possibly using this answer here to "call a function" without parentheses).
Infix function
// Add to prototype so that it's always there for you
Object.prototype._ = function(binaryOperator){
// The first operand is captured in the this keyword
let operand1 = this;
// Use a proxy to capture the second operand with "get"
// Note that the first operand and the applied function
// are stored in the get function's closure, since operand2
// is just a string, for eval(operand2) to be in scope,
// the value for operand2 must be defined globally
return new Proxy({},{
get: function(obj, operand2){
return binaryOperator(operand1, eval(operand2))
}
})
}
Also note that the second operand is passed as a string and evaluated with eval
to get its value. Because of this, I think the code will break anytime the value of operand (aka "b") is not defined globally.
Javascript doesn't include an infix notation for functions or sections for partial application. But it ships with higher order functions, which allow us to do almost everything:
// applicator for infix notation
const $ = (x, f, y) => f(x) (y);
// for left section
const $_ = (x, f) => f(x);
// for right section
const _$ = (f, y) => x => f(x) (y);
// non-commutative operator function
const sub = x => y => x - y;
// application
console.log(
$(2, sub, 3), // -1
$_(2, sub) (3), // -1
_$(sub, 3) (2) // -1
);
As you can see I prefer visual names $
, $_
and _$
to textual ones in this case. This is the best you can get - at least with pure Javascript/ES2015.
You can get close by function currying:
const $ = (a) => (f) => f(a);
const plus = (a) => (b) => (a+b);
const twoPlusThree = $ (2) (plus) (3);
But I still haven't figured out a neat way to compose this construction.
© 2022 - 2024 — McMap. All rights reserved.
foo
you wouldn't know abouta
, would you? So it's not possible to actually do infix stuff... And typicallya
would be a value rather than a function, which is also problematic with the OP's example. – Enthrall