1. ホーム
  2. lambda

[解決済み] ラムダってなんだろう?

2023-02-27 11:16:37

質問

みんなが言い続けている「ラムダ」とは何でしょうか?多くの人がそれを好きなようですが、私がそこから得られるものは、たくさんのコードの行を単一の式に詰め込む方法だということだけです。

誰かその真価について教えてくれませんか?

どのように解決するのですか?

名前のない関数

簡単に言うと、ラムダは名前のない関数、または無名関数です。実行可能なコードの小さなピースで、あたかも変数のように渡すことができます。JavaScriptでは

function () {}; // very simple

では、これらのラムダの使い方をいくつか見てみましょう。

定型的なコードを抽象化する

ラムダは定型的なコードを抽象化するために使われることがあります。例えばループです。私たちはよく forwhile のループを一日中繰り返しています。しかし、これは書かないコードです。ループの中のコード、つまり最も重要な部分を抽出して、残りを抽象化すればいいのです。

for (var i=0; i<array.length; i++) {
    // do what something useful with array[i]
}

を使うことで forEach の配列オブジェクトの、になります。

array.forEach(function (element, index) {
   // do something useful with element
   // element is the equivalent of array[i] from above
});

上記の抽象化はそれほど便利ではないかもしれませんが、他にも高次の関数として、例えば forEach のような、より有用なタスクを実行する高次関数があります。例えば filter :

var numbers = [1, 2, 3, 4];
var even    = [];

// keep all even numbers from above array
for (var i=0; i<numbers.length; i++) {
    if (numbers[i] % 2 === 0) {
        even.push(numbers[i]);
    }
}

alert(even);

// Using the filter method
even = [1, 2, 3, 4].filter(function (number) {
    return number % 2 === 0;
});

alert(even);

コード実行遅延

イベントという概念がある環境では、ある時点で起こるかもしれないイベントに対応するためにラムダを使うことができます。

window.onload = function () {
    alert("Loaded");
};

window.setTimeout(function () {
    alert("Code executed after 2 seconds.");
}, 2000);

これは他の方法でも可能でしたが、それらはかなり冗長です。例えば、Javaでは Runnable というインタフェースがあります。

関数のファクトリー

ここまで、私たちはラムダをその構文解析の能力のためだけに使ってきました。しかし、ラムダがもっと役に立つ状況もあります。例えば、ラムダを返す関数があるかもしれません。その戻り値をキャッシュしたい関数があるとします。

var users = [];
var getUser = function (name) {
    if (! users[name]) {
        // expensive operations to get a user. Ajax for example
        users[name] = user_from_ajax;
    }

    return users[name];
};

後日、似たような機能があることに気づくかもしれません。

var photos = [];
var getPhoto = function (name) {
    if (! photo[name]) {
        // expensive operations to get a user. Ajax for example
        photos[name] = photo_from_ajax;
    }

    return photos[name];
};

明らかにパターンがあるので、それを抽象化してみましょう。そこで メモ書き .

/**
 * @param {Array}     store Data structure in which we cache lambda's return values
 * @param {Function}  lambda
 * @return {Function} A function that caches the result of calling the lambda param
 */
var memoize = function (store, lambda) {
    // return a new lambda
    return function (name) {
        if (! store[name]) {
            // Execute the lambda and cache the result
            store[name] = lambda(name);
        }

        return store[name];
    };
};

var getUsers = memoize([], function (name) {
    // expensive operations to get a user. Ajax for example
});

var getPhotos = memoize([], function (name) {
    // expensive operations to get a photo. Ajax for example
});

ご覧の通り、ラムダを使うことで、キャッシュ/メモライゼーションロジックを抽象化することができました。他の例では回避策があったとしても、この特定の問題は他の手法ではほとんど解決できないと思っています。私たちは、重要な定型的なコードを一箇所に集めることができました。言うまでもないことですが、私たちは usersphotos というグローバル変数があります。

あなたのプロフィールを見ると、ほとんどPythonのユーザーですね。上記のパターンについて、Pythonにはデコレータという概念があります。たくさんの の例がネット上にたくさんあります。 のデコレータがたくさんあります。唯一の違いは、Pythonではほとんどの場合 という名前の という名前の関数がそのデコレータ関数の中にネストされていることです。Pythonは単一式のラムダしかサポートしていないからです。しかし、コンセプトは同じです。

Pythonのラムダの使用例として。偶数をフィルタリングした上記のコードは、Pythonでは次のように表現できます。

filter(lambda x: x % 2 == 0, [1, 2, 3, 4])

とにかく、ラムダはクロージャなしにはそれほど強力ではありません。クロージャはラムダの概念を強力にするものです。私のメモ化の例では、クロージャを使って store パラメーターを囲むクロージャーを作りました。この方法だと memoize 関数がその結果(ラムダ)を返した後でも、私はそのパラメータにアクセスすることができます。