Skip to content

Instantly share code, notes, and snippets.

@jennings
Last active June 30, 2017 06:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jennings/b2d8849747bb52dfdac56a2501f13a10 to your computer and use it in GitHub Desktop.
Save jennings/b2d8849747bb52dfdac56a2501f13a10 to your computer and use it in GitHub Desktop.
Function currying in JavaScript

A simple function for allowing partial function application in JavaScript.

function foo(a, b, c) {
    return [a, b, c]
}

var bar = foo.curry(1, 2)
bar(3)                      // => [1, 2, 3]

Even if enough arguments are provided, the underlying function is not evaluated until the returned function is evaluated.

var baz = foo.curry(1, 2, 3)
baz()                       // => [1, 2, 3]

this will be bound when the underlying function is evaluated.

function what_is_this() {
    return "This is " + this + "!"
}

var fn = what_is_this.curry()
fn.call("Sparta")           // => "This is Sparta!"
Function.prototype.curry = function () {
var fn = this
var curriedArgs = Array.prototype.slice.call(arguments)
var curriedFunction = function () {
// Copy args so this curried function can be reused
var args = curriedArgs.slice()
// Gather the additional arguments from this invocation
for (var i = 0; i < arguments.length; i++) {
args.push(arguments[i])
}
return fn.apply(this, args)
}
// Set a reasonable name so we see it in the debugger
var curriedName = (fn.name || '(anonymous)') + '_curried:' + curriedArgs.length
Object.defineProperty(curriedFunction, 'name', { value: curriedName })
return curriedFunction
}
require('./curry.js')
describe("Function.prototype.curry", function () {
it("assigns 'this' when the curried function is called", function() {
var f = function () { return this }
var expected = {}
expected.g = f.curry(expected)
var result = expected.g()
expect(result).toBe(expected)
})
it("does not call the function when some parameters are provided", function() {
var called = false
var f = function (a, b, c) { called = true; return { a: a, b: b, c: c } }
var g = f.curry(1)
expect(called).toBe(false)
var h = g.curry(2)
expect(called).toBe(false)
var result = h(3)
expect(called).toBe(true)
})
it("does not call the function when all parameters are provided", function() {
var called = false
var f = function (a, b, c) { called = true; return { a: a, b: b, c: c } }
var g = f.curry(1, 2, 3)
expect(called).toBe(false)
var result = g()
expect(called).toBe(true)
})
it("works with nullary functions", function() {
var f = function () { return 1 }
var g = f.curry()
var result = g()
expect(result).toBe(1)
})
it("works with unary functions", function() {
var f = function (a) { return { a: a } }
var g = f.curry(1)
var result = g()
expect(result.a).toBe(1)
})
it("works with binary functions passed with one argument", function() {
var f = function (a, b) { return { a: a, b: b } }
var g = f.curry(1)
var result = g(2)
expect(result.a).toBe(1)
expect(result.b).toBe(2)
})
it("works with binary functions with two arguments", function() {
var f = function (a, b) { return { a: a, b: b } }
var g = f.curry(1, 2)
var result = g(3)
expect(result.a).toBe(1)
expect(result.b).toBe(2)
})
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment