views:

166

answers:

6

Here is a lisp procedure that simply adds 'a' to the absolute value of 'b':

(define (a-plus-abs-b a b)
  ((if (> b 0) + -) a b))

I think this is beautiful, and I am trying to find the best way of writing this in JavaScript. But my JavaScript code is not beautiful:

var plus = function(a,b) {
    return a + b;
};

var minus = function(a,b) {
    return a - b;
};

var aPlusAbsB = function(a,b) {
    return (b > 0 ? plus : minus)(a,b);
}

The main problem is that I cannot use the + and - symbols as references to the functions they really represent as I can with lisp. Can anyone come up with a more graceful way of doing something like this, or have I hit a language boundary?

Obviously, I can do this:

var aPlusAbsB = function(a,b) {
    return a + Math.abs(b);
}

, but this is more of a thought experiment than a pragmatic question.

Is there any way I can get reference to the core functions in the JavaScript language just as if they were user-defined?

+5  A: 

It's a very cool idea - would be great for evaluating mathematical expressions but you simply can't set an operator (or the logic behind it) to a variable. Sorry :-)

Andy E
I hate to give you a +1 for the OP's sake, but it's true, there's little you can do about it.
musicfreak
@musicfreak: lol thanks ;-) I often thought about this because there have been times when I've had to check the state of a variable to decide whether to `+` or `-`, but it would have been so much cooler if I could have just passed the `+` or `-` instead - it would have saved a whole `if` statement!
Andy E
Unless proven otherwise by some roving JavaScript maven, this seems like the answer :(.
Matthew Taylor
A: 

This is slightly more beautiful than your suggestion, though nowhere near as beautiful as your lisp representation of the concept:

var aPlusAbsB = function(a, b) {
    var plus = function(a, b) {
      return a + b;
    };
    var minus = function(a, b) {
      return a - b;
    };
    return (b > 0 ? plus : minus)(a, b);
}

This would be equivalent to the following in scheme:

(define a-plus-abs-b
  (lambda (a b)
    (let ((plus (lambda (a b) (+ a b))) (minus (lambda (a b) (- a b))))
      (cond ((> b 0) (plus a b))
      (else (minus a b))))))
ecounysis
+3  A: 

Though not as elegant as the LISP code, you could create a function dynamically that acts like an operator (on numbers), but it's not.

function op(o) {
    return new Function("a", "b", "return a " + o + " b");
}


function aPlusAbsB(a, b) {
    return (b > 0 ? op('+') : op('-'))(a, b);
}

Additionally, we can hide the complexity of generating these inside an if wrapper, but that's the closest I can get :)

function is(expr, op1, op2) {
    return expr ? op(op1) : op(op2);
}

function aPlusAbsB(a, b) {
    return (is(b > 0, '+', '-')(a, b));
}
Anurag
+1  A: 

I think everyone else got here first, but JS is slightly less purely functional than lisp, operators are not functions or objects, but operators.

ysaw
+5  A: 

It depends on what aspects of the lisp implementation you find particularly beautiful. I'll propose another version of your suggestion that I think ends up a little closer to your lisp definition's syntax by doing some dirty things.

// Give ourselves + and - functions to level the playing field with lisp.
Number.prototype['+'] = function(x)this+x;
Number.prototype['-'] = function(x)this-x;

// Now we can have some fun.
var aPlusAbsB = function(a,b) a [b > 0 ? '+' : '-'] (b);

// Some other notable language barrier differences, but not too dissimilar?
// (define (a-plus-abs-b a b) ((if (> b 0) + -) a b))
Kevin
A: 

Yeah, that's not strictly possible, the closest thing you can do is nest addition and subtraction functions inside.

var aPlusAbsB = function(a, b) {
    return (function(a, b) { b > 0 ? a + b : a - b })(a, b);
}

Not exactly the same, but it gets the job done in a sufficiently indirect way.

Blair Mitchelmore