Create a gist now

Instantly share code, notes, and snippets.

The distinction between anonymous functions and lambdas in JavaScript.

TL;DR - Lambda means "function used as data".

Anonymous function means "function without a name".

This is one of the relatively few cases where the Wikipedia definition of a word, while not entirely wrong, is misleading. Lambdas and anonymous functions are distinct ideas.

These ideas are commonly confused because in many programming languages (and lambda calculus) all lambdas are anonymous or vise verse.

In JavaScript, not all lambdas are anonymous, and not all anonymous functions are lambdas, so the distinction has some practical meaning.

(function () {
  console.log(`
  Some people mistakenly think that "lambda" and "anonymous function" have
  the same meaning. Let's clear that up.

  In computer science, the most important, defining characteristic of a lambda
  expression is that it is used as data. That is, the function is passed as
  an argument to another function, returned as a value from a function, or
  assigned to variables or data structures.

  This is basically the definition of a first class function. In JavaScript, you
  can use any function as a lambda expression because functions are first class.

  However, that does not mean that all JavaScript functions are therefore lambda
  expressions. For instance, this expression defines a function which gets
  immediately invoked and then dropped on the floor rather than passed,
  exported, or assigned. In other words, the function is not used as data.
  Instead, it's used for a side-effect (logging this text to the console).

  Conceptually, this is more akin to imperative programming than functional
  programming, and thinking of this function as a lambda would add zero useful
  meaning to your understanding of it.

  This distinction is not essential, but is a useful concept when you're
  learning functional programming. In other words, if you understand this
  distinction, you have a deeper understanding of what the word "lambda" means
  in both functional programming and lambda calculus (which are closely
  related).

  It is possible to use functional language features like first-class functions
  in an imperative style, but that adds nothing interesting to your grasp of the
  language, or your grasp of why lambda expressions exist in the first place.
  `)
})();

$('#el').on('click', function clickHandler () {
  console.log(`
  This is an example of a lambda expression that is not anonymous. As you can
  see, it clearly has a name, clickHandler, which can be used inside the
  function for the purpose of recursion (also an important concept in functional
  programming).

  It is a lambda expression because of the semantic use -- it's being passed
  to another function as data. The .on() function is using the function as
  an argument -- in other words, communicated as a message (i.e. functions as
  data).
  `);
});

Looks like some people are still confused, because you've accepted "lambda = anonymous" as gospel. While it is a somewhat useful concept to understand that anonymous functions have interesting uses, such as points-free-style (tacit programming), that is not the salient point of lambdas. It's mostly syntactical sugar.

I am aware that hundreds of references refer to lambdas and anonymous functions interchangeably, and that lots of references list "anonymous function" as the definition of "lambda".

I'm saying they're wrong, and the distinction matters in JavaScript in order to avoid confusion when you learn functional programming concepts.

It is functions used as data which is the true salient, defining feature of lambdas, not anonymity.

For example, you can have all the same benefits of anonymous functions even when those functions have names, simply by ignoring the names.

However, there are benefits to named lambdas that you can't enjoy without the names, such as enhanced debugging visibility.

The point here is that whether a function has a name or not is not particularly important compared to whether or not the function is used as data. JavaScript supports named and unnamed lambdas, and it's useful to understand that a named function can be anonymous. If you don't consider a named function to be a lambda, you're missing the point of lambdas.

bar is a lambda, but not anonymous:

const foo = [1,2,3];
const baz = foo.map(function bar (n) { return n + 1; });

This anonymous function is not a lambda:

// Just evaluated and dropped on the floor. Not used as data.

// Not a lambda.

(msg) => {

  const formattedMsg = JSON.stringify({
    time: Date.now(),
    msg
  });
  console.log(formattedMsg)

}('foo');

`

@dfkaye
dfkaye commented May 19, 2015

I was running this by copy+paste in the console to see the template string output, but w/o including jQuery.

To do that successfully, here's a quick-and-dirty $ shim:

var $ = function $() { return { on: $} };

And this line

$('#el').on(click, function clickHandler () {

Should be changed to

$('#el').on('click', function clickHandler () { // add quotes around 'click'

Then it works 😄

@ericelliott
Owner

Fixed.

@kbariotis

And if we had omitted the clickHandler function's name and instead left it anonymous. What would that be? (As bad practice as that is)

@oieduardorabelo

@kbariotis still be an lambda

Lambda means "function used as data".

if the function is named or not, "doesn't matter" (we can explain why named function is good, debugging and recursion, but, you know what I mean)

@fiskr
fiskr commented Aug 18, 2015

I'm uncertain of what you mean by "lambda" here.
When you posted this on twitter, you received a comment like:

Brutallo: @_ericelliott Strictly speaking, in lambda calculus functions are always anonymous.

To which you replied:

Eric Elliott: @Brutallo JavaScript isn't lambda calculus. ;)

So then what do you mean by lambda?
I know Python has a special keyword for lambda, as does Scheme.
But I'm not familiar with anything like that for Javascript, the closest might be the function keyword.
Essentially, what could you mean by lamdba here other than in the context of lambda calculus?

If you really are making a distinction between anonymous functions in javascript and lambdas like Scheme might use, then I'm further confused by your distinction.

If you read 1.3.2, when lambda is introduced in SICP, it sure seems that lambda is being used to make anonymous functions.

In fact, if your read about anonymous functions, you find quotes like:

In several programming languages, anonymous functions are introduced using the keyword lambda, and anonymous functions are often referred to as lambdas or lambda abstractions.

Is the distinction you are making really something more along the lines of "lambda is a functional programming paradigm, and when you use a lambda in an imperative way, it's not useful to think of it as a lambda anymore"?

Unfortunately, just because it's not useful to think of an anonymous function as a lambda doesn't make it not a lambda. This leaves me in knots trying to understand your distinction.

Back to SICP, would the following be an example of "imperative" use of a lambda?
(lambda (x) (/ 1.0 (* x (+ x 2))))
The above code is also "immediately invoked and then dropped on the floor rather than passed,
exported, or assigned" - but it is still a lambda no?

So what distinction are you really making?

What specifically can I read to understand this distinction, and what are your sources?

Don't confuse my challenge as an attack - I think this is fun stuff, and you more than likely know what you're talking about - that just means I need some help to catch up. Help me out. 😃

@Apromixately

If you hit somebody with a broom it doesn't suddenly become a bat.

@battlmonstr
battlmonstr commented Aug 21, 2016 edited

Interesting point, but it is biased to JavaScript. JavaScript can't be a model language for that Wikipedia article. When lambda functions are available in most languages you can find diverse examples of what is called a lambda function and deduce the meaning.
Consider this:

  1. In most programming languages if a function is anonymous it can't be called, unless it's assigned or passed as an argument (used as data). The JavaScript idiom of defining a function to be called once and dropped is an esoteric way to deal with scopes. It started mainly as a hack to cope with problems of not having block-scope local variables, and not having safe isolated namespaces (defining a named function XYZ in the global scope accidentally overrides window.XYZ).
  2. "Function used as data" is a required attribute, but not sufficient to qualify as a lambda function. With that definition function pointers and callbacks are also lambdas, but they aren't. Other important attributes are:
    • a function that is defined in place where it's used
    • a function that is defined using a shorthand arrow notation. Most languages have arrow notations these days, but those which didn't (like PHP 5 or JS ES 5) could call their anonymous function syntax "lambda functions" with a stretch.

Examples:

    function next(n) { return n + 1 }
    [1,2,3].map(next)
        // not a lambda function, although used as data

    [1,2,3].map(function (n) { return n + 1 })
        // anonymous function, but not a lambda function
        // (can call it a lambda function in loosely terms)

    [1,2,3].map(n => n + 1)
         // true lambda function expression
@ergose
ergose commented Sep 5, 2016 edited

I am in disagreement that a function is still a lambda once one names the function.

It sounds like, in lamda calculus, the functions are all anonymous and, I'm assuming, are called lambdas in discussion.
At some point in time the term pollinated into JavaScript discussions to describe functions that were anonymous.
Ultimately, I'm of the stance that the term lambda, is merely a synonymous term for an anonymous function.

Where that description is misleading, however, is when practically applied, anonymous functions tend to be passed as data in JavaScript.
When learning about lambdas in the context of lambda calculus there is no conflict. It sounds like it is strictly a term for the functions.
When learning in the context of JavaScript, to say that a lambda is strictly an anonymous function is still technically correct,
but it looses real world meaning when one considers how it's actually used, the majority of the time, in a JS discussion...
Usually it is assumed that one is using the term lambda to not, literally mean just an anonymous function, but one that is being
used as data (since that's often how the lambda/anonymous function is used in an applied JavaScript context.)

If I were describing a lambda to someone in a JS discussion that was new to the concept then I would describe it as,
"an anonymous function, often used as data, and to return data, for an invoking function." I feel it would convey the clearest meaning
without diving into examples or being too general.

Borrowing from battlmonstr and the author, here's what I do and don't consider lambdas:

const foo = [1,2,3];
const baz = foo.map(function bar (n) { return n + 1; });
    // I would not call this a lambda function because it is named.
    // The term I would use in discussion would be a Named Function.
    // ex: "We are passing the Named Function bar into foo.map"

function next(n) { return n + 1 }
[1,2,3].map(next)
    // I would not call this a lambda function because it is named.
    // The term I would use is a Callback in discussion.

[1,2,3].map(function (n) { return n + 1});
    // I would call this a lambda function because it is an anonymous function, 
    // used as data, and returns data, for an invoking function.
    // I would say that I was "passing a lambda to dot map."

[1,2,3].map( n => n + 1 );
    // I would also call this a lambda for the same reason.
    // I would say the same as above.

I consider the last two functions as completely equal, neither being more true, because:
"[1,2,3].map( n => n + 1 );" transpiles directly to "[1,2,3].map(function (n) { return n + 1});" with TypeScript (I'm pretty sure it's
the same with Babel.)

I've really enjoyed reading and thinking about this. :) Kudos.

@amandeepmittal

Is this an example of Lambda function or anonymous function?

var functionName = function(a,b,c){};

In the above example a function is created and assigned a name: functionName

@Madeyedexter

This article definitely clears the mist around lambdas and anonymous functions. Thank you.

@fromSpace

The function "Passed as data" is still anonymous to the receiving function, it will be evaluated regardless of it's name. Keeping a reference to that function via the lexical scope makes it more difficult to troubleshoot / test unless you knew something about the function before it was passed to you. If I start passing functions that take advantage of the "private" closure around it to access itself, there is magic behind the scenes that may cause hard to track errors. It is best to reference the function by the argument name in the recieving function, you will be able to do recursion there if required. I do not believe passing as anonymous without a name limits the ability to unit test the function, the function you have access to from within the closure and the recieving function would not share the same execution thread, and though you can use it for recursion, there is a performance cost with that type of recursion because you never return from the previous function when it calls itself. This type of recursion absolutely does cause multiple execution threads to be opened simultaniously, but provides the added benefit of asynchronicity. I recommend registering your evented action type as a string in queue somewhere, then processing your que item from the event handler, if required, you could pass a string query to the event. The reason I pass the definition and register as a string is because a reference will not be maintained within the closure of the function that you want to completely die at next GC, and you will be able maintain the same asynchronous recursion, without the overhead. Essentially, you can have an asynchrounous method called consistently over 5 hours and the memory peak when watching the profiler in chrome will always be the same height. If you are using the type of recursion you had mentioned in this post, you essentially have a memory leak.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment