Untuk memberikan jawaban singkat, makro digunakan untuk mendefinisikan ekstensi sintaksis bahasa ke Common Lisp atau Domain Specific Languages (DSLs). Bahasa-bahasa ini tertanam langsung ke dalam kode Lisp yang ada. Sekarang, DSL dapat memiliki sintaksis yang mirip dengan Lisp (seperti Prolog Interpreter Peter Norvig untuk Common Lisp) atau yang sama sekali berbeda (mis. Infix Notation Math for Clojure).
Berikut adalah contoh yang lebih konkret:
Python memiliki daftar pemahaman yang dibangun ke dalam bahasa. Ini memberikan sintaksis sederhana untuk kasus umum. Garis
divisibleByTwo = [x for x in range(10) if x % 2 == 0]
menghasilkan daftar yang berisi semua angka genap antara 0 dan 9. Kembali di Python 1,5 hari tidak ada sintaksis seperti itu; Anda akan menggunakan sesuatu yang lebih seperti ini:
divisibleByTwo = []
for x in range( 10 ):
if x % 2 == 0:
divisibleByTwo.append( x )
Keduanya setara secara fungsional. Mari kita memohon penangguhan ketidakpercayaan kita dan berpura-pura Lisp memiliki makro loop yang sangat terbatas yang hanya melakukan iterasi dan tidak ada cara mudah untuk melakukan yang setara dengan pemahaman daftar.
Di Lisp Anda bisa menulis yang berikut ini. Saya harus mencatat contoh yang dibuat ini dipilih untuk menjadi identik dengan kode Python bukan contoh yang baik dari kode Lisp.
;; the following two functions just make equivalent of Python's range function
;; you can safely ignore them unless you are running this code
(defun range-helper (x)
(if (= x 0)
(list x)
(cons x (range-helper (- x 1)))))
(defun range (x)
(reverse (range-helper (- x 1))))
;; equivalent to the python example:
;; define a variable
(defvar divisibleByTwo nil)
;; loop from 0 upto and including 9
(loop for x in (range 10)
;; test for divisibility by two
if (= (mod x 2) 0)
;; append to the list
do (setq divisibleByTwo (append divisibleByTwo (list x))))
Sebelum saya melangkah lebih jauh, saya harus menjelaskan apa itu makro. Ini adalah transformasi yang dilakukan pada kode dengan kode. Yaitu, sepotong kode, dibaca oleh interpreter (atau kompiler), yang mengambil kode sebagai argumen, memanipulasi dan mengembalikan hasilnya, yang kemudian dijalankan di tempat.
Tentu saja itu banyak mengetik dan programmer malas. Jadi kita bisa mendefinisikan DSL untuk melakukan pemahaman daftar. Bahkan, kami sudah menggunakan satu makro (loop makro).
Lisp mendefinisikan beberapa bentuk sintaks khusus. Kutipan ( '
) menunjukkan token berikutnya adalah literal. Kuasiquote atau backtick ( `
) menunjukkan token berikutnya adalah literal dengan lolos. Lolos ditunjukkan oleh operator koma. Secara literal '(1 2 3)
adalah setara dengan Python [1, 2, 3]
. Anda dapat menetapkannya ke variabel lain atau menggunakannya di tempat. Anda dapat menganggapnya `(1 2 ,x)
sebagai yang ekivalen dengan Python di [1, 2, x]
mana x
variabel yang sebelumnya didefinisikan. Notasi daftar ini adalah bagian dari keajaiban yang masuk ke makro. Bagian kedua adalah pembaca Lisp yang secara cerdas mengganti makro untuk kode tetapi yang paling baik digambarkan di bawah ini:
Jadi kita bisa mendefinisikan makro yang disebut lcomp
(kependekan dari daftar pemahaman). Sintaksnya akan persis seperti python yang kita gunakan dalam contoh [x for x in range(10) if x % 2 == 0]
-(lcomp x for x in (range 10) if (= (% x 2) 0))
(defmacro lcomp (expression for var in list conditional conditional-test)
;; create a unique variable name for the result
(let ((result (gensym)))
;; the arguments are really code so we can substitute them
;; store nil in the unique variable name generated above
`(let ((,result nil))
;; var is a variable name
;; list is the list literal we are suppose to iterate over
(loop for ,var in ,list
;; conditional is if or unless
;; conditional-test is (= (mod x 2) 0) in our examples
,conditional ,conditional-test
;; and this is the action from the earlier lisp example
;; result = result + [x] in python
do (setq ,result (append ,result (list ,expression))))
;; return the result
,result)))
Sekarang kita bisa mengeksekusi di baris perintah:
CL-USER> (lcomp x for x in (range 10) if (= (mod x 2) 0))
(0 2 4 6 8)
Cukup rapi, ya? Sekarang tidak berhenti di situ. Anda memiliki mekanisme, atau kuas, jika Anda mau. Anda dapat memiliki sintaks yang mungkin Anda inginkan. Seperti with
sintaksis Python atau C # . Atau sintaks. LINQ .NET Pada akhirnya, inilah yang menarik orang ke Lisp - fleksibilitas tertinggi.