TL; DR Seperti yang ditunjukkan orang lain: notasi lambda hanyalah cara untuk mendefinisikan fungsi tanpa dipaksa untuk memberi mereka nama.
Versi panjang
Saya ingin menguraikan sedikit tentang topik ini karena saya merasa sangat menarik. Penafian: Saya sudah lama mengikuti kalkulus lambda. Jika seseorang dengan pengetahuan yang lebih baik menemukan kesalahan dalam jawaban saya, jangan ragu untuk membantu saya meningkatkannya.
Mari kita mulai dengan ekspresi, misalnya 1 + 2
dan x + 2
. Literal seperti 1
dan 2
disebut konstanta karena terikat dengan nilai tetap tertentu.
Identifier seperti x
disebut variabel dan untuk mengevaluasinya Anda harus mengikatnya ke beberapa nilai terlebih dahulu. Jadi, pada dasarnya Anda tidak dapat mengevaluasi x + 1
selama Anda tidak tahu apa x
itu.
Notasi lambda menyediakan skema untuk mengikat nilai input spesifik ke variabel. Sebuah ekspresi lambda dapat dibentuk dengan menambahkan λx .
di depan sebuah ekspresi yang ada, misalnya λx . x + 1
. Variabel x
dikatakan bebas di x + 1
dan terikat diλx . x + 1
Bagaimana ini membantu dalam mengevaluasi ekspresi? Jika Anda memberi nilai pada ekspresi lambda, seperti itu
(λx . x + 1) 2
maka Anda dapat mengevaluasi seluruh ekspresi dengan mengganti (mengikat) semua kemunculan variabel x
dengan nilai 2:
(λx . x + 1) 2
2 + 1
3
Jadi, notasi lambda menyediakan mekanisme umum untuk mengikat hal-hal ke variabel yang muncul dalam blok ekspresi / program. Bergantung pada konteksnya, ini menciptakan konsep yang sangat berbeda dalam bahasa pemrograman:
- Dalam bahasa murni fungsional seperti Haskell, ekspresi lambda mewakili fungsi dalam arti matematika: nilai input disuntikkan ke dalam tubuh lambda dan nilai output dihasilkan.
- Dalam banyak bahasa (misalnya JavaScript, Python, Skema) mengevaluasi tubuh ekspresi lambda dapat memiliki efek samping. Dalam hal ini orang dapat menggunakan istilah prosedur untuk menandai perbedaan fungsi murni.
Terlepas dari perbedaan, notasi lambda adalah tentang mendefinisikan parameter formal dan mengikatnya ke parameter aktual.
Langkah selanjutnya, adalah memberi fungsi / prosedur nama. Dalam beberapa bahasa, fungsi adalah nilai seperti yang lain, sehingga Anda dapat memberi nama fungsi sebagai berikut:
(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
Seperti yang ditunjukkan Eli Barzilay, definisi ini hanya mengikat nama f
pada suatu nilai, yang kebetulan merupakan suatu fungsi. Jadi dalam hal ini, fungsi, angka, string, karakter adalah semua nilai yang dapat diikat ke nama dengan cara yang sama:
(define n 42) ;; Scheme
n = 42 -- Haskell
val n: Int = 42 // Scala
var n = 42 // JavaScript
n = 42 # Python
Dalam bahasa ini Anda juga dapat mengikat fungsi ke nama menggunakan notasi yang lebih akrab (tapi setara):
(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
Beberapa bahasa, misalnya C, hanya mendukung notasi terakhir untuk mendefinisikan (bernama) fungsi.
Penutupan
Beberapa pengamatan terakhir tentang penutupan . Pertimbangkan ungkapannya x + y
. Ini mengandung dua variabel gratis. Jika Anda mengikat x
menggunakan notasi lambda Anda mendapatkan:
\x -> x + y
Ini bukan (belum) fungsi karena masih berisi variabel gratis y
. Anda bisa membuat fungsi dengan mengikat y
juga:
\x -> \y -> x + y
atau
\x y -> x + y
yang sama dengan +
fungsinya.
Tetapi Anda dapat mengikat, katakanlah, y
dengan cara lain (*):
incrementBy y = \x -> x + y
Hasil penerapan kenaikan fungsi Dengan angka adalah penutupan, yaitu fungsi / prosedur yang badannya berisi variabel bebas (misalnya y
) yang telah terikat pada nilai dari lingkungan di mana penutupan didefinisikan.
Begitu incrementBy 5
juga fungsi (penutupan) yang menambah angka dengan 5.
CATATAN (*)
Saya sedikit curang di sini:
incrementBy y = \x -> x + y
setara dengan
incrementBy = \y -> \x -> x + y
jadi mekanisme pengikatannya sama. Secara intuitif, saya berpikir tentang penutupan sebagai mewakili sebagian dari ekspresi lambda yang lebih kompleks. Ketika representasi ini dibuat, beberapa binding dari ekspresi ibu telah ditetapkan dan penutupan menggunakannya nanti ketika akan dievaluasi / dipanggil.