Sự khác biệt giữa một chức năng và lambda là gì?


54

Tôi hơi bối rối về 'chức năng' và 'lambda'. Tôi đã thấy một số ví dụ cho thấy từ khóa lược đồ lambdahoạt động rất giống với từ khóa JavaScript function, nhưng tôi thực sự không biết chúng có liên quan như thế nào.

Tôi đã nói rằng 'hàm' và 'phương thức' có thể được sử dụng thay thế cho nhau khi nói về các đối tượng trong .net. Tôi tự hỏi liệu 'lambda' và 'chức năng' có cùng một ý nghĩa như nhau không. Tôi tự hỏi nếu 'lambda' có một số ý nghĩa bí truyền, khi thấy rằng chữ lambda (λ) của Hy Lạp xuất hiện trong rất nhiều avatar trên trang web này. Để làm cho mọi thứ trở nên khó hiểu hơn, trong .net, các phần chức năng của C # đề cập đến các biểu thức chức năng được chuyển đến một chức năng khác là 'biểu thức lambda', vì vậy từ này dường như ở khắp mọi nơi.

Tôi cũng mơ hồ quen thuộc với thuật ngữ 'lambda tính toán'.

Sự khác biệt giữa một chức năng và lambda là gì?


3
Nitpick - chúng được gọi là "biểu thức lambda", không phải là "hàm lambda", ít nhất là theo tài liệu C # /. NET.
Oded

@ TWith2Sugars - Đọc tin nhắn. Câu trả lời của bạn là chất lượng thấp vì nó khá nhiều chỉ là một liên kết, vì vậy đã được chuyển đổi thành một nhận xét.
Oded

17
I wonder if 'lambda' has some esoteric meaning, seeing that the Greek letter lambda (λ) appears in so many avatars on this site.Người ta sẽ hy vọng nó sẽ liên quan đến tính toán lambda, nhưng tôi có một cảm giác kỳ lạ Half Life là đổ lỗi cho avatar lambda.
yannis

3
Đủ công bằng, đây là liên kết đến câu trả lời stackoverflow
TWith2Sugars

@ZaphodBeeblebrox: Tôi nghi ngờ bạn đúng về ảnh hưởng của Half-Life. : /
Thất vọngWithFormsDesigner

Câu trả lời:


44

Từ "lambda" hoặc "biểu thức lambda" thường dùng để chỉ các hàm ẩn danh. Vì vậy, theo nghĩa đó, lambda là một loại chức năng, nhưng không phải mọi chức năng đều là lambda (nghĩa là các chức năng được đặt tên thường không được gọi là lambdas). Tùy thuộc vào ngôn ngữ, các hàm ẩn danh thường được triển khai khác với các hàm được đặt tên (đặc biệt là trong các ngôn ngữ mà các hàm ẩn danh là các hàm đóng và các hàm được đặt tên là không), do đó, việc đề cập đến chúng với các thuật ngữ khác nhau có thể có ý nghĩa.

Sự khác biệt giữa từ khóa lambda của lược đồ và từ khóa chức năng của Javascript là cái sau có thể được sử dụng để tạo cả hàm ẩn danh và hàm được đặt tên trong khi cái trước chỉ tạo hàm ẩn danh (và bạn sẽ sử dụng defineđể tạo hàm có tên).

Phép tính lambda là một mô hình tính toán / ngôn ngữ lập trình tối thiểu, sử dụng các hàm làm "cấu trúc dữ liệu" duy nhất của nó. Trong phép tính lamdba, biểu tượng lambda được sử dụng để tạo các hàm (ẩn danh). Đây là nơi sử dụng thuật ngữ "lambda" trong các ngôn ngữ khác.


1
Đó là vô cùng thô bạo. Bạn sử dụng define(hoặc letmột trong những người thân của nó hoặc xác định nội bộ) để tạo tên - đó là tất cả. Không có gì đặc biệt defineliên quan đến chức năng.
Eli Barzilay

2
@EliBarzilay Vâng, define không có một hình thức đặc biệt để xác định chức năng (ví dụ: bạn có thể viết (define (f x) (foo))thay vì (define f (lambda (x) (foo)))), nhưng quan điểm của tôi là bạn không thể tạo một hàm có tên sử dụng lambdamột mình, tức là bạn không thể viết một cái gì đó giống như (lambda f (x) (foo))để xác định một hàm có tên fcó một đối số như bạn có thể làm với functiontừ khóa của Javascript .
sepp2k

1
definecó như một đường cú pháp, vì vậy nó không quan trọng bằng vai trò của nó như là một công cụ liên kết tên cho tất cả các giá trị. Đối với việc lambdakhông tự tạo tên: đó là một tính năng quan trọng, vì nó tách biệt việc đặt tên với các dạng hàm ... IMO JS đang làm điều đúng đắn trong việc cho phép phân tách trong khi cũng chấp nhận một tên tùy chọn cho những người đó sẽ kinh hoàng ý tưởng của một chức năng không có tên. (Và may mắn là kích thước của những người đó đang suy giảm chung ...)
Eli Barzilay

18

Lambda đơn giản là một hàm ẩn danh - một hàm không có tên.


4
Lưu ý Khá: lambda có thể chứa trạng thái (như trong bao đóng) mà chúng tách khỏi bối cảnh nơi chúng được khai báo.
Martin York

7
Vì vậy, một hàm được đặt tên, nếu ngôn ngữ cho phép bạn khai báo các hàm lồng nhau.
cHao

4
Kudos đã đưa nó vào tab đánh giá "bài viết chất lượng thấp" với câu trả lời nâng cao.
yannis

@ZaphodBeeblebrox - Không cố ý, tôi có thể đảm bảo với bạn.
Oded

Không thực sự, một lambdabiểu thức trong Lược đồ giống như một functionbiểu thức không có tên - nhưng không có gì ngăn bạn sau này đặt tên cho chúng. Ví dụ var f = [function(x){return x;}][0]. Bạn có thể lập luận rằng giá trị hàm tự nó không có tên, nhưng điều đó đúng với tất cả các hàm ...
Eli Barzilay


8

Trong C # Hàm ẩn danh là một thuật ngữ chung bao gồm cả biểu thức lambda và phương thức ẩn danh (phương thức ẩn danh là trường hợp ủy nhiệm không có khai báo phương thức thực tế).

Biểu thức Lambda có thể được chia thành biểu thức lambdatuyên bố lambda

Biểu hiện lambda:

(int x, string y) => x == y.Length 

Câu lệnh lambda tương tự như biểu thức lambda ngoại trừ (các) câu lệnh được đặt trong dấu ngoặc nhọn:

(int x, string y) => {
         if (x == y.Length) {
             Console.WriteLine(y);
         }
}

Khi chúng ta nói về các biểu thức lambda trong JavaScript, về cơ bản chỉ có nghĩa là sử dụng một hàm làm đối số trong một cuộc gọi đến một chức năng khác.

var calculate = function(x, y, operation){
    return operation(x, y);
}

// we're passing anonymous function as a third argument
calculate(10, 15, function(x, y) {
    return x + y;
}); // 25

+1 Rất nhiều người đã đề cập rằng lambdas là các chức năng ẩn danh, nhưng có nhiều điều hơn thế. Cơ thể (phía bên tay phải) của lambda thường là một biểu thức chứ không phải là một khối câu lệnh. Phần thân của một hàm được đặt tên là một biểu thức thường được cho phép (hoặc bắt buộc) trong các ngôn ngữ chức năng, nhưng không phải là ngôn ngữ bắt buộc.
Zantier

4

TL; DR Như những người khác đã chỉ ra: ký hiệu lambda chỉ là một cách để xác định các hàm mà không bị buộc phải đặt tên cho chúng.

Phiên bản dài

Tôi muốn giải thích một chút về chủ đề này vì tôi thấy nó rất thú vị. Tuyên bố miễn trừ trách nhiệm: Tôi đã tham gia khóa học về tính toán lambda từ lâu. Nếu ai đó có kiến ​​thức tốt hơn tìm thấy bất kỳ sự không chính xác trong câu trả lời của tôi, vui lòng giúp tôi cải thiện nó.

Hãy bắt đầu với các biểu thức, ví dụ 1 + 2x + 2. Các nghĩa đen như 12được gọi là hằng số vì chúng bị ràng buộc với các giá trị cố định cụ thể.

Một định danh như xđược gọi là biến và để đánh giá nó, trước tiên bạn cần liên kết nó với một số giá trị. Vì vậy, về cơ bản, bạn không thể đánh giá x + 1chừng nào bạn chưa biết nó xlà gì .

Ký hiệu lambda cung cấp một lược đồ để liên kết các giá trị đầu vào cụ thể với các biến. Một biểu thức lambda có thể được hình thành bằng cách thêm λx .vào trước một biểu thức hiện có, ví dụ λx . x + 1. Biến xđược cho là miễn phí trong x + 1ràng buộc trongλx . x + 1

Làm thế nào điều này giúp trong việc đánh giá biểu thức? Nếu bạn cung cấp một giá trị cho biểu thức lambda, như vậy

(λx . x + 1) 2

sau đó bạn có thể đánh giá toàn bộ biểu thức bằng cách thay thế (ràng buộc) tất cả các lần xuất hiện của biến xbằng giá trị 2:

(λx . x + 1) 2
      2 + 1
      3

Vì vậy, ký hiệu lambda cung cấp một cơ chế chung để liên kết mọi thứ với các biến xuất hiện trong một khối biểu thức / chương trình. Tùy thuộc vào ngữ cảnh, điều này tạo ra các khái niệm khác nhau về ngôn ngữ lập trình:

  • Trong một ngôn ngữ chức năng thuần túy như Haskell, các biểu thức lambda thể hiện các hàm theo nghĩa toán học: một giá trị đầu vào được đưa vào phần thân của lambda và một giá trị đầu ra được tạo ra.
  • Trong nhiều ngôn ngữ (ví dụ JavaScript, Python, Scheme) đánh giá phần thân của biểu thức lambda có thể có tác dụng phụ. Trong trường hợp này, người ta có thể sử dụng thủ tục hạn để đánh dấu các hàm thuần túy wrt.

Ngoài sự khác biệt, ký hiệu lambda là về việc xác định các tham số chính thức và ràng buộc chúng với các tham số thực tế.

Bước tiếp theo, là đặt tên cho hàm / thủ tục. Trong một số ngôn ngữ, các hàm là các giá trị như bất kỳ ngôn ngữ nào khác, vì vậy bạn có thể đặt tên cho hàm như sau:

(define f (lambda (x) (+ x 1)))      ;; Scheme

f = \x -> x + 1                      -- Haskell

val f: (Int => Int) = x => x + 1     // Scala

var f = function(x) { return x + 1 } // JavaScript

f = lambda x: x + 1                  # Python

Như Eli Barzilay đã chỉ ra, những định nghĩa này chỉ liên kết tên fvới một giá trị, điều này xảy ra là một hàm. Vì vậy, về mặt này, các hàm, số, chuỗi, ký tự là tất cả các giá trị có thể được liên kết với các tên theo cùng một cách:

(define n 42)   ;; Scheme

n = 42          -- Haskell

val n: Int = 42 // Scala

var n = 42      // JavaScript

n = 42          # Python

Trong các ngôn ngữ này, bạn cũng có thể liên kết một chức năng với một tên bằng cách sử dụng ký hiệu quen thuộc hơn (nhưng tương đương):

(define (f x) (+ x 1))         ;; Scheme

f x = x + 1                    -- Haskell

def f(x: Int): Int = x + 1     // Scala

function f(x) { return x + 1 } // JavaScript

def f(x): return x + 1         # Python

Một số ngôn ngữ, ví dụ C, chỉ hỗ trợ ký hiệu sau để xác định hàm (được đặt tên).

Đóng cửa

Một số quan sát cuối cùng liên quan đến việc đóng cửa . Hãy xem xét biểu thức x + y. Điều này chứa hai biến miễn phí. Nếu bạn liên kết xbằng cách sử dụng ký hiệu lambda, bạn sẽ nhận được:

\x -> x + y

Đây không phải là (chưa) một hàm vì nó vẫn chứa một biến miễn phí y. Bạn cũng có thể tạo một hàm từ nó bằng cách ràng buộc y:

\x -> \y -> x + y

hoặc là

\x y -> x + y

đó là giống như +chức năng.

Nhưng bạn có thể liên kết, nói, ytheo một cách khác (*):

incrementBy y = \x -> x + y

Kết quả của việc áp dụng tăng hàmBy cho một số là một bao đóng, tức là một hàm / thủ tục có phần thân chứa một biến tự do (ví dụ y) đã được liên kết với một giá trị từ môi trường trong đó đóng được xác định.

Vậy incrementBy 5là hàm (đóng) tăng số lên 5.

GHI CHÚ (*)

Tôi đang gian lận một chút ở đây:

incrementBy y = \x -> x + y

tương đương với

incrementBy = \y -> \x -> x + y

do đó cơ chế ràng buộc là như nhau. Theo trực giác, tôi nghĩ về việc đóng cửa như thể hiện một đoạn biểu hiện lambda phức tạp hơn. Khi biểu diễn này được tạo, một số ràng buộc của biểu thức mẹ đã được đặt và bao đóng sẽ sử dụng chúng sau này khi nó được đánh giá / gọi.


Tôi chỉ là người mới bắt đầu, nhưng tôi nghĩ điều này có thể hơi khó hiểu nếu bạn đang cố gắng hiểu λ phép tính theo nghĩa toán học, vì những gì bạn gọi là hằng được gọi là biến và được biểu thị bằng các ký hiệu a, b, c ... Bạn là gì các biến gọi sẽ là một biến không xác định x . Mặt khác 1 là λ f x . f x , 2 là λ f x . f ( f x ) và như vậy.
jinawee

@jinawee: Tôi thừa nhận tôi đã không tra cứu định nghĩa chính xác. Tôi nhớ sử dụng các thuật ngữ biến và hằng trong logic. Ở đó, hằng số là một biểu tượng được ánh xạ tới một miền, trong khi đó một biến là một biểu tượng bạn có thể định lượng được. Nhưng, một lần nữa, (1) đã lâu rồi kể từ khi tôi tham gia một khóa học về logic và (2) lambda-compus không cần phải tuân theo 1-1 các khái niệm về logic toán học. Nếu bạn chỉ cho tôi một tài liệu tham khảo, tôi có thể thử và sửa chữa thuật ngữ của mình.
Giorgio

0

"Lambda" trong lập trình thường có nghĩa là "hàm lambda" (hay còn gọi là "biểu thức lambda", "thuật ngữ lambda"). Khi hàm là một khối mã được đặt tên được xác định trước khi sử dụng, "hàm lambda" là một khối mã (hoặc một biểu thức) được định nghĩa thay cho việc sử dụng có thể được sử dụng như một công dân hạng nhất trong ngôn ngữ lập trình.

Trong JavaScript ES6 (2015) có một cú pháp ngắn để định nghĩa lambdas gọi là "Hàm mũi tên" . Trong C # cú pháp như vậy đã được giới thiệu trong .NET 3.0 (khoảng năm 2006) .

Trong toán học, một khái niệm "hàm" có một số ý nghĩa trong đó một trong những ý nghĩa là về ký hiệu của hàm (nghĩa là làm thế nào để viết nó xuống), thì "hàm lambda" (trong phép tính) là một loại ký hiệu hàm đặc biệt. Để thảo luận thêm, hãy kiểm tra các hàm lambda trong các ngôn ngữ lập trình .

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.