1

I am currently learning functional programming using Underscore.js. What I want to do is add two co-ordinates together. Let P1 = (0, 0) and P2 = (1, 1). Therefore, P1 + P2 = (1, 1)

I have a solution, but it seems so convoluted that I'm sure I'm doing something wrong:

// Base 2D Cartesian Point
var Point = function(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.add = function(delta) {
  return _.object(_.keys(this),
    _.map(
      _.zip(
        _.values(this), 
        _.values(delta)), 
        function(point) {
          return _.reduce(point, 
            function(memo, num) { return memo + num; }, 0);
        }
    )
  );
}

Is this the proper implementation of the add function for points using Underscore.js or is there a better solution?

  • What prevents you from simply adding two points together using ordinary Javascript arithmetic? – Robert Harvey Feb 22 '14 at 4:32
  • I had that originally, but for some reason, I had this feeling that it could be done with reduce or map somehow. I guess if I just added two points together it would be the easiest, but I figured there was some way to use the functional language to implement this. I'm a complete noob at functional programming, so I'm not sure what's the best way to approach this problem. – Pete Feb 22 '14 at 4:33
1

Learning functional programming doesn't mean to forget what you already know. For fixed two-dimensional coordinates, I would just use the following:

sum = [p1[0] + p2[0], p1[1] + p2[1]]

If you don't know the dimension of your coordinates, or if it's large, the next best in this case is to use a list comprehension, which for some reason a lot of people forget about, or don't think it's "functional enough," because it resembles a for loop. However, it is more powerful than a for loop as it is an expression that can be assigned, can be evaluated lazily, and is parallelizable if you don't introduce side effects.

sum = (p1[i] + p2[i] for i in [0..(p1.length - 1)])

If you had a bunch of these to do, like addition, subtraction, multiplication, etc. you typically would create a function to do the iteration, which takes another function as an argument for what you want to do to each pair. It would look like this:

corresponding = (p1, p2, f) -> f(p1[i], p2[i]) for i in [0..(p1.length - 1)]

And you would use it like this:

sum  = corresponding(p1, p2, (i, j) -> i + j)
diff = corresponding(p1, p2, (i, j) -> i - j)
prod = corresponding(p1, p2, (i, j) -> i * j)

Granted, that's not much shorter than the list comprehension, but a real world corresponding function would probably be significantly longer due to error handling.

Note that these examples are in CoffeeScript, as I'm not familiar with underscore.js, but the solutions are fairly typical of functional programming.

  • I didn't know about List Comprehension. It looks very useful and definitely cleans it up a lot. Thanks for sharing this answer! It's very clean and maintainable. – Pete Feb 22 '14 at 20:06
2

If you're going to do functional programming on points, it would make more sense for your points to be lists of coordinates instead of objects. That simplifies the code quite a bit:

function add(p1, p2) {
    _.map(_.zip(p1, p2), function(coords) {
        return _.reduce(coords, function(coord, sum) { return sum + coord; }, 0);
    });
}

This may make sense if you're dealing with ten dimensional space, but it seems like overkill for two dimensions.

  • I'm beginning to see how functional programming is a separation of data and methods. It does seem to promote a lot of reuse and separator of duty. Definitely takes a lot more thinking to generalize the methods, but I suspect that over time it will get easier. – Pete Feb 22 '14 at 20:05
0

There are several methods you can use to perform this calculation. I am going to use your base 2d point object and extend it a couple of ways

// Base 2D Cartesian Point
var Point = function(x, y) {
  this.x = x;
  this.y = y;
};

Since Robert Harvey's suggestion is so straight forward, let's start with it:

var startpoint = new Point(0, 0);
var offsetpoint = new Point(startpoint.x + 5, startpoint.y + 5);

Next, you can add a function to the Point instance already created:

Point.add = function(x, y) {
  this.x += x;
  this.y += y;
};

As you have shown above, you can also modify the class prototype by changing Point.add to Point.prototype.add. The revised declaration adds the add method to all Point instances.

Suppose you want to pass a Point instead of x and y? We can do that too. We just can't use a polymorphic method declaration. We can, however, morph the function into a new function with different parameters. The down side to this is that, from that point on, you will not ever be able to get back to the first implementation with x and y without replacing the function again. That's probably too much for right now. Let's add the next version:

Point.prototype.addPoint = function(anotherPoint) {
    // Is the object being passed in of our class?
    if(anotherPoint instanceof Point) {
      this.add(anotherPoint.x, anotherPoint.y);
    }
};

Here is a jsfiddle with this code working.

  • With this, would it be better to take in two points to keep Point from being mutable? – Pete Feb 22 '14 at 20:03
  • That would be a matter of opinion. Everything in javascript is mutable, so I would think that it wouldn't matter. – Adam Zuckerman Feb 22 '14 at 20:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.