'Lambda' mà mọi người vẫn nhắc đến là gì?


93

'Lambda' mà mọi người vẫn nhắc đến là gì? Rất nhiều người có vẻ yêu thích nó, nhưng tất cả những gì tôi có thể thu thập được từ nó là nó chỉ là một cách nhồi nhét rất nhiều dòng mã vào một biểu thức duy nhất.

Ai đó có thể vui lòng khai sáng cho tôi về giá trị thực sự của nó không?


16
Tôi có thể chỉ ra cho người trả lời rằng người hỏi nơi nào đề cập .net


Câu hỏi bẻ khóa. Cam ơn vi đa hỏi.
Peanut

Lambdas thuộc thế giới của lập trình hàm (Lập trình so sánh).
RBT

Câu trả lời:


179

Các hàm không có tên

Nói một cách đơn giản, lambda là một hàm không có tên hoặc một hàm ẩn danh. Một đoạn mã thực thi nhỏ, có thể được truyền xung quanh như thể nó là một biến. Trong JavaScript:

function () {}; // very simple

Bây giờ chúng ta hãy xem một số sử dụng cho những lambdas này.

Tóm tắt mã bảng soạn sẵn

Lambdas có thể được sử dụng để trừu tượng hóa mã soạn sẵn. Ví dụ các vòng lặp. Chúng ta thường viết forwhilelặp lại suốt cả ngày. Nhưng đây là mã không được viết. Chúng ta có thể trích xuất mã bên trong vòng lặp, phần quan trọng nhất của vòng lặp và tóm tắt phần còn lại:

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

bằng cách sử dụng các forEachđối tượng mảng, trở thành:

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

Sự trừu tượng ở trên có thể không hữu ích, nhưng có những hàm bậc cao khác, như forEach, thực hiện các tác vụ hữu ích hơn nhiều. Ví dụ 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);

Độ trễ thực thi mã

Trong một số môi trường có sẵn khái niệm sự kiện, chúng ta có thể sử dụng lambdas để phản hồi các sự kiện có thể xảy ra tại một thời điểm nào đó.

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

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

Điều này có thể được thực hiện theo một số cách khác, nhưng những cách đó khá dài dòng. Ví dụ, trong Java có Runnablegiao diện.

Các nhà máy của các chức năng

Cho đến thời điểm này, chúng tôi chỉ sử dụng lambdas cho khả năng đường cú pháp của nó là chủ yếu. Nhưng có những tình huống mà lambdas có thể hữu ích hơn nhiều. Ví dụ, chúng ta có thể có các hàm trả về lambdas. Giả sử chúng ta có một hàm mà chúng ta muốn các giá trị trả về của nó được lưu vào bộ nhớ đệm.

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];
};

Sau đó, chúng ta có thể nhận thấy rằng chúng ta có một chức năng tương tự:

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];
};

Rõ ràng có một mô hình trong đó, vì vậy hãy trừu tượng hóa nó đi. Hãy sử dụng ghi nhớ .

/**
 * @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
});

Như bạn có thể thấy, bằng cách sử dụng lambdas, chúng tôi đã có thể trừu tượng hóa logic bộ nhớ đệm / ghi nhớ. Nếu ví dụ khác có một số cách giải quyết, tôi tin rằng vấn đề cụ thể này hầu như không được giải quyết bằng cách sử dụng các kỹ thuật khác. Chúng tôi đã quản lý để trích xuất một số mã bảng soạn sẵn quan trọng vào một nơi duy nhất. Chưa kể rằng chúng tôi đã loại bỏ các biến usersphotostoàn cục.

Nhìn vào hồ sơ của bạn, tôi thấy rằng bạn chủ yếu là người dùng Python. Đối với mẫu trên, Python có khái niệm về trình trang trí. Có rất nhiều ví dụ trên mạng về trang trí ghi nhớ . Sự khác biệt duy nhất là trong Python, bạn rất có thể có một hàm lồng nhau được đặt tên bên trong hàm decorator đó. Lý do là Python chỉ hỗ trợ lambdas một biểu thức. Nhưng khái niệm là như nhau.

Như một ví dụ về việc sử dụng Python lambda. Đoạn mã trên mà chúng tôi đã lọc các số chẵn có thể được biểu diễn bằng Python như thế này:

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

Dù sao đi nữa, lambdas không mạnh đến thế nếu không đóng cửa. Đóng cửa là điều làm cho khái niệm lambdas trở nên mạnh mẽ. Trong ví dụ ghi nhớ của tôi, tôi đã sử dụng các bao đóng để tạo một bao đóng xung quanh storetham số. Bằng cách này, tôi có quyền truy cập vào tham số đó ngay cả sau khi memoizehàm đã trả về kết quả (lambda).


3
Chà, bạn đã dành rất nhiều thời gian cho việc đó.
mk12

4
@ Mk12, trong văn bản thực tế của câu trả lời, không thực sự. Trong học tập công cụ này, yeah, nó được một thời gian kể từ khi tôi bắt đầu :)
Ionuţ G. Stan

Câu trả lời tốt nhưng thiếu thông tin về "giao diện chức năng" (theo quan điểm Java).
djangofan

Các toán tử "===" đó trong "Mã bảng soạn sẵn trừu tượng" của bạn là gì?
Don


19

Thuật ngữ "lambda" được sử dụng để chỉ một hàm ẩn danh, thường là một bao đóng . Chúng hữu ích bởi vì chúng cho phép bạn viết các hàm sử dụng các hàm khác mà không làm tăng mã của bạn một cách không cần thiết. Ví dụ, trong Ruby:

(1..100).select {|num| num % 2 == 0}

Điều này sẽ tạo ra một mảng chứa các số chẵn từ 1 đến 100. Chúng ta không phải viết ra một vòng lặp rõ ràng - phương thức select lấy một hàm mà nó sử dụng để kiểm tra các giá trị, vì vậy tất cả những gì chúng ta cần là logic tùy chỉnh của chúng ta. Điều này cho phép chúng tôi tùy chỉnh rất nhiều phương pháp mà thực tế không tốn nhiều công sức hoặc chi phí. Về cơ bản, chúng ta có thể soạn các hàm từ các hàm nhỏ hơn.

Đó chỉ là một ví dụ dễ hiểu về những gì họ có thể làm. Khả năng truyền các hàm dưới dạng dữ liệu thực sự mạnh mẽ và các lập trình viên ngôn ngữ hàm thường làm một số điều thực sự tuyệt vời với nó.


6
Có lẽ bạn nên thêm rằng thứ trong các đường ống là tham số. Tôi là một trong những người gặp khó khăn khi đọc ruby.
Skurmedel

Đây là một câu trả lời hay. Lý do duy nhất Ionut có được phiếu bầu của tôi là anh ấy nói với chúng tôi lý do tại sao chúng tôi nên quan tâm (chi tiết) về lambdas.
Frank Shearar,

Tôi sẽ không đồng ý rằng lambdas thường đóng cửa.
jwg

6

"Lambda" có lẽ quá ít. Hãy xem phép tính Lambda . Nó hữu ích trong lập trình chức năng.

Và lập trình chức năng là một mô hình lập trình khác (như thủ tục hoặc hướng đối tượng).


5
Sau đó, mọi người nói về "Lambda", rất có thể họ đang nói về hàm ẩn danh, con trỏ hàm, bao đóng hoặc một cái gì đó tương tự. Hầu như không bao giờ đề cập đến điều tính toán lambda thực sự.
J-16 SDiZ

Rất vui vì bạn đã đề cập đến phép tính Lambda.! +1.
RBT

5

Lambdas trong .NET thường được gọi là "đường cú pháp". Chúng không ảnh hưởng trực tiếp đến chức năng tuy nhiên chúng giúp mọi người sử dụng ngôn ngữ dễ dàng hơn.

Khi bạn đã hiểu sức mạnh của việc sử dụng chúng, tôi chắc chắn rằng bạn sẽ thấy rằng bạn sẽ viết ít mã hơn so với cách cũ theo cách sử dụng các phương thức ủy quyền / ẩn danh.


1
Tôi không nghĩ có ai đã đề cập đến .NET, vì vậy OP có lẽ tốt hơn nên có một câu trả lời tổng quát hơn.
molf

2
đó là lý do tại sao tôi đã làm rõ bằng câu trả lời về .net. Nếu những người khác thích thú với việc triển khai ngôn ngữ của họ thì q & a sẽ giúp ích cho nhiều người bất kể họ lựa chọn ngôn ngữ nào.
redsquare

Câu trả lời này giống như bạn đã nghe điều gì đó về lambdas, nhưng bản thân bạn vẫn chưa hiểu chúng.
jwg

2

Tiến sĩ Dobbs Journal có một bài viết hữu ích giới thiệu các biểu thức lambda (trong ngữ cảnh của C ++ nhưng tôi nghĩ bạn có thể áp dụng các nguyên tắc cho bất kỳ ngôn ngữ nào).

Như bài báo nói: "Biểu thức lambda là một biểu thức rất nhỏ gọn không yêu cầu định nghĩa lớp / hàm riêng biệt."

Vì vậy, sử dụng các ví dụ về danh sách 1 & 2 từ DDJ thay vì viết:

std::for_each( vec.begin(), vec.end(), print_to_stream<std::string>(std::cout));

Yêu cầu định nghĩa lớp riêng biệt như:

template <typename T, typename Stream> class print_to_stream_t {
  Stream& stream_;
public:
  print_to_stream_t(Stream& s):stream_(s) {}
  void operator()(const T& t) const {
    stream_ << t;
  }
};
template <typename T,typename Stream> 
print_to_stream_t<T,Stream>   print_to_stream(Stream& s) {
  return print_to_stream_t<T,Stream>(s);
}

Sử dụng thư viện Boost lambda, điều này có thể trở thành:

std::for_each(vec.begin(),vec.end(),std::cout << _1);

Mà giữ cho định nghĩa nội dòng.

Bài báo cũng giải thích thêm một số ứng dụng của biểu thức lambda.

Tôi nghĩ rằng một điểm chính trong bài viết DDJ là "Thông thường, biểu thức lambda được sử dụng khi các hàm nhỏ và không quá phức tạp là cần thiết tại trang web cuộc gọi. Nếu hàm không tầm thường, bạn sẽ không muốn biểu thức lambda mà là một hàm bình thường hoặc một đối tượng chức năng. "


2

Nếu bạn đã từng làm việc với các hàm / phương thức sử dụng con trỏ hàm, đại biểu, chiến lược hoặc mẫu quan sát / xử lý sự kiện và tự nghĩ "Tôi đang viết toàn bộ hàm này chỉ để sử dụng nó một lần - hãy chuyển nó cho phương thức này ; Tôi ước tôi có thể viết nó tại chỗ, thay vì làm lộn xộn mã của tôi "- đó là nơi bạn có thể sử dụng các hàm Lambda. Các ngôn ngữ hỗ trợ cấu trúc này cũng thường tận dụng nhiều lợi thế của khái niệm truyền hàm dưới dạng tham số, đặc biệt liên quan đến làm việc với danh sách (hàm hạng nhất và hàm bậc cao). Điều này đặc biệt đúng đối với các ngôn ngữ hàm, dựa vào cấu tạo hàm hơn là sửa đổi bộ nhớ để tính toán. Trong một số trường hợp (bằng các ngôn ngữ như Python),


2

'lambda' qua từ là thuật ngữ từ những ngày mà các loại khoa học máy tính thường được đào tạo về toán học hoặc logic hơn là có bằng cấp về khoa học máy tính. Một số người trong số họ đã tạo ra một mô hình gọi là 'lập trình chức năng', hoàn toàn khác với mệnh lệnh và cũng khá mạnh mẽ. AFAIK đó là điều kiện nơi thuật ngữ này được sử dụng.

Các nhà toán học và logic học được cho là sử dụng những từ kỳ lạ.

'lambda' nghe thực sự bí truyền - như thể chúng là một thứ rất kỳ lạ và đặc biệt. Thực sự, nếu bạn viết JavaScript cho một ứng dụng trình duyệt web và sử dụng thành ngữ "var foo = function () {...}", bạn đã sử dụng các hàm lambda từ lâu rồi.


1

Biểu thức lambda là một dạng hàm đơn giản. Ý tưởng là một cái gì đó có dạng ở bên trái (tương đương với các tham số) trở thành một cái gì đó có dạng ở bên phải (tương đương với phần thân).

ví dụ, trong c sharp:

x => x * x

là một lambda để bình phương một giá trị. Một cái gì đó của hình thức

x

trở thành một cái gì đó của hình thức

x * x

0

"Biểu thức lambda là một hàm ẩn danh có thể chứa các biểu thức và câu lệnh, đồng thời có thể được sử dụng để tạo các đại biểu hoặc các kiểu cây biểu thức.

Tất cả các biểu thức lambda đều sử dụng toán tử lambda =>, được đọc là "đi tới". Phía bên trái của toán tử lambda chỉ định các tham số đầu vào (nếu có) và phía bên phải chứa biểu thức hoặc khối câu lệnh. Biểu thức lambda x => x * x được đọc là "x chuyển đến x lần x."

từ MSDN


4
Vâng, Microsoft khiến mọi người nghĩ rằng họ đã phát minh ra nó. Tuy nhiên, biểu thức Lambda có trước Microsoft. Đó là một thuật ngữ toán học đã được áp dụng cho một số ngôn ngữ lập trình. (Đó là có thể, kể từ toán học có thể được coi là một ngôn ngữ máy tính bằng cách riêng của mình.)
Wim ten Brink

4
Lưu ý rằng điều này dành riêng cho việc triển khai .Net của Microsoft. Nó không phải là một sự sai lệch lớn so với ý tưởng chung về lambda, nhưng tôi nghĩ rằng chức năng được triển khai trong Lisp là "tiêu chuẩn" hơn.
Chuck

2
Câu trả lời đó hoàn toàn không giải thích Lambda là gì (cần định nghĩa về hàm ẩn danh, đại biểu, kiểu cây biểu thức) và chắc chắn không giải thích giá trị của nó là gì.
danio

0

Để có lời giải thích đầy đủ về các biểu thức Lambda, hãy xem Wikipedia . (Cuộn xuống phần giải tích Lambda và ngôn ngữ lập trình .) Biểu thức Lambda không phải là quá mới và chúng không chỉ là một phần của C # mà là một thứ đã được đưa vào máy tính gần 80 năm trước! Biểu thức Lambda là cơ sở để lập trình hàm.

Giá trị của nó? Vâng, xét rằng nó thực sự khá cũ, tôi sẽ nói: rất có giá trị đối với bất kỳ ai làm tính toán.


0

Nếu bạn yêu thích Java, bạn đã quan tâm rất nhiều đến lambdas hoặc việc đóng cửa trong vài tháng qua, bởi vì có nhiều đề xuất khác nhau để thêm tính năng này vào Java 7. Tuy nhiên, tôi nghĩ rằng comitee đã bỏ nó. Một trong những đề xuất là của Neal Gafter và được giải thích rất chi tiết tại đây: javac.info . Điều này đã giúp tôi hiểu các trường hợp sử dụng và lợi thế (đặc biệt là so với các lớp bên trong)




-1

Vâng, nó chỉ là một cách nhồi nhét rất nhiều dòng mã vào một biểu thức duy nhất. Nhưng là một cách nhồi nhét hiệu quả như vậy, nó cho phép một số cách mới để cấu trúc chương trình của bạn.

Thông thường, người ta sẽ tránh viết các ủy nhiệm hoặc lệnh gọi lại và chuyển về kiểu thủ tục đơn giản vì quá nhiều việc để khai báo các hàm hoặc lớp mới cho một biểu thức duy nhất.

Các biểu thức Lambda khiến việc sử dụng các lệnh gọi lại trở nên hữu ích ngay cả đối với các tác vụ nhỏ nhất, điều này có thể làm cho mã rõ ràng hơn. Có thể không.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.