Tính toán lambda là một mô hình tính toán được phát minh bởi Alonzo Church trong những năm 30. Cú pháp và ngữ nghĩa của hầu hết các ngôn ngữ lập trình chức năng được lấy cảm hứng trực tiếp hoặc gián tiếp từ phép tính lambda.
Phép tính lambda ở dạng cơ bản nhất có hai thao tác: Trừu tượng (tạo hàm (ẩn danh)) và ứng dụng (áp dụng hàm). Sự trừu tượng hóa được thực hiện bằng cách sử dụng toán tử, đưa ra phép tính lambda tên của nó.
- Biểu thức Lambda
- Hàm Lambda
Các hàm ẩn danh thường được gọi là "lambdas", "hàm lambda" hoặc "biểu thức lambda" bởi vì, như tôi đã nói ở trên, là biểu tượng để tạo các hàm ẩn danh trong phép tính lambda (và từ lambda
này được sử dụng để tạo các hàm ẩn danh trong nhiều ngôn ngữ ngôn ngữ dựa trên cùng một lý do).
Đây không phải là một thuật ngữ thường được sử dụng, nhưng tôi cho rằng nó có nghĩa là lập trình bằng cách sử dụng các hàm ẩn danh hoặc lập trình bằng các hàm bậc cao hơn.
Thêm một chút thông tin về lambdas trong C ++ 0x, động lực của chúng và cách chúng liên quan đến con trỏ chức năng (rất nhiều điều này có thể là sự lặp lại của những gì bạn đã biết, nhưng tôi hy vọng nó giúp giải thích động lực của lambdas và chúng khác nhau như thế nào từ con trỏ hàm):
Các con trỏ hàm, đã tồn tại trong C, khá hữu ích để chuyển một hàm so sánh sang một hàm sắp xếp. Tuy nhiên, có những giới hạn cho tính hữu dụng của chúng:
Ví dụ: nếu bạn muốn sắp xếp một vectơ của vectơ theo i
phần tử thứ của mỗi vectơ (trong đó i
là tham số thời gian chạy), bạn không thể giải quyết điều này bằng một con trỏ hàm. Một hàm so sánh hai vectơ theo i
phần tử thứ của chúng , sẽ cần lấy ba đối số ( i
và hai vectơ), nhưng hàm sắp xếp sẽ cần một hàm lấy hai đối số. Những gì chúng ta cần là một cách nào đó để cung cấp đối số i
cho hàm trước khi chuyển nó sang hàm sắp xếp, nhưng chúng ta không thể làm điều này với các hàm C đơn giản.
Để giải quyết điều này, C ++ đã giới thiệu khái niệm "đối tượng hàm" hoặc "hàm xử lý". Một functor về cơ bản là một đối tượng có một operator()
phương thức. Bây giờ chúng ta có thể định nghĩa một lớp CompareByIthElement
, lấy đối số i
làm đối số hàm tạo và sau đó lấy hai vectơ được so sánh làm đối số cho operator()
phương thức. Để sắp xếp một vectơ của vectơ theo i
phần tử th, bây giờ chúng ta có thể tạo một CompareByIthElement
đối tượng với i
tư cách là một đối số và sau đó chuyển đối tượng đó sang hàm sắp xếp.
Vì các đối tượng hàm chỉ là các đối tượng và không phải là các hàm kỹ thuật (mặc dù chúng có nghĩa là hoạt động giống như chúng), bạn không thể tạo một con trỏ hàm trỏ đến một đối tượng hàm (tất nhiên bạn có thể có một con trỏ tới một đối tượng hàm, nhưng nó sẽ có một kiểu như CompareByIthElement*
và do đó không phải là một con trỏ hàm).
Hầu hết các hàm trong thư viện chuẩn C ++, lấy các hàm làm đối số được xác định bằng cách sử dụng các mẫu để chúng hoạt động với các con trỏ hàm cũng như các đối tượng hàm.
Bây giờ đến lambdas:
Việc xác định cả một lớp để so sánh bởi i
phần tử thứ là một chút dài dòng nếu bạn chỉ sử dụng nó một lần để sắp xếp một vectơ. Ngay cả trong trường hợp bạn chỉ cần một con trỏ hàm, việc xác định hàm được đặt tên là tối ưu nếu nó chỉ được sử dụng một lần vì a) nó gây ô nhiễm không gian tên và b) hàm thường sẽ rất nhỏ và thực sự không có một lý do chính đáng để trừu tượng hóa logic thành chức năng của chính nó (ngoài việc bạn không thể có các con trỏ hàm mà không xác định hàm).
Vì vậy, để sửa chữa lambdas này đã được giới thiệu. Lambdas là các đối tượng chức năng, không phải con trỏ hàm. Nếu bạn sử dụng [x1, x2](y1,y2){bla}
mã lambda giống như mã được tạo, về cơ bản sẽ thực hiện như sau:
- Xác định một lớp có hai biến thành viên (
x1
và x2
) và một operator()
với các đối số ( y1
và y2
) và phần thân bla
.
- Tạo một thể hiện của lớp, đặt các biến thành viên
x1
và x2
các giá trị của các biến x1
và x2
hiện trong phạm vi.
Vì vậy, lambdas hoạt động giống như các đối tượng chức năng, ngoại trừ việc bạn không thể truy cập vào lớp được tạo để thực hiện lambda theo bất kỳ cách nào khác ngoài việc sử dụng lambda. Do đó, bất kỳ hàm nào chấp nhận hàm functor làm đối số (về cơ bản có nghĩa là bất kỳ hàm không C nào trong thư viện chuẩn), sẽ chấp nhận lambdas, nhưng bất kỳ hàm nào chỉ chấp nhận con trỏ hàm sẽ không.