Có rất nhiều ngôn ngữ cho phép một số loại siêu lập trình . Đặc biệt, tôi ngạc nhiên khi thấy không có câu trả lời nào nói về gia đình ngôn ngữ Lisp .
Từ wikipedia:
Metaprogramming là viết các chương trình máy tính với khả năng coi các chương trình là dữ liệu của chúng.
Sau đó trong văn bản:
Lisp có lẽ là ngôn ngữ tinh túy với các phương tiện siêu lập trình, cả vì ưu tiên lịch sử của nó và vì tính đơn giản và sức mạnh của siêu lập trình của nó.
Ngôn ngữ Lisp
Một phần giới thiệu nhanh chóng để Lisp theo sau.
Một cách để xem mã là một bộ hướng dẫn: làm điều này, sau đó làm điều đó, sau đó làm điều khác ... Đây là một danh sách! Một danh sách những điều cho chương trình để làm. Và tất nhiên bạn có thể có danh sách bên trong danh sách để thể hiện các vòng lặp, v.v.
Nếu chúng ta đại diện cho một danh sách có chứa các yếu tố a, b, c, d như thế này: (abcd), chúng tôi có được cái gì đó trông giống như một cuộc gọi chức năng Lisp, nơi a
là chức năng, và b
, c
, d
là các đối số. Nếu thực tế là "Hello World!" chương trình có thể được viết như vậy:(println "Hello World!")
Tất nhiên b
, c
hoặc d
có thể là danh sách đánh giá một cái gì đó là tốt. Sau đây: (println "I can add :" (+ 1 3) )
sau đó sẽ in "" Tôi có thể thêm: 4 ".
Vì vậy, một chương trình là một chuỗi các danh sách lồng nhau và phần tử đầu tiên là một hàm. Tin tốt là chúng ta có thể thao túng danh sách! Vì vậy, chúng ta có thể thao tác ngôn ngữ lập trình.
Lợi thế Lisp
Lisps không có nhiều ngôn ngữ lập trình nhiều như một bộ công cụ để tạo ngôn ngữ lập trình. Một ngôn ngữ lập trình lập trình.
Điều này không chỉ dễ dàng hơn nhiều trong việc tạo ra các toán tử mới, mà gần như không thể viết một số toán tử bằng các ngôn ngữ khác vì các đối số được đánh giá khi được truyền vào hàm.
Ví dụ, trong một ngôn ngữ giống như C, hãy nói rằng bạn muốn if
tự mình viết một toán tử, đại loại như:
my-if(condition, if-true, if-false)
my-if(false, print("I should not be printed"), print("I should be printed"))
Trong trường hợp này, cả hai đối số sẽ được đánh giá và in, theo thứ tự phụ thuộc vào thứ tự đánh giá của các đối số.
Trong Lisps, viết một toán tử (chúng ta gọi nó là macro) và viết một hàm là về cùng một thứ và được sử dụng theo cùng một cách. Sự khác biệt chính là các tham số cho macro không được đánh giá trước khi được chuyển dưới dạng đối số cho macro. Điều này là cần thiết để có thể viết một số toán tử, như if
trên.
Ngôn ngữ trong thế giới thực
Hiển thị chính xác như thế nào là một chút ngoài phạm vi ở đây, nhưng tôi khuyến khích bạn hãy thử lập trình trong một Lisp để tìm hiểu thêm. Chẳng hạn, bạn có thể xem qua:
- Lược đồ , một Lisp cũ, khá "tinh khiết" với lõi nhỏ
- Lisp thông thường, một Lisp lớn hơn với hệ thống đối tượng được tích hợp tốt và nhiều triển khai (nó được chuẩn hóa ANSI)
- Vợt một Lisp đánh máy
- Clojure yêu thích của tôi, các ví dụ ở trên là mã Clojure. Một Lisp hiện đại chạy trên JVM. Có một số ví dụ về macro Clojure trên SO (nhưng đây không phải là nơi thích hợp để bắt đầu. Tôi sẽ xem xét 4clojure , braveclojure hoặc clojure koans )).
Oh và nhân tiện, Lisp có nghĩa là Xử lý LISt.
Về ví dụ của bạn
Tôi sẽ đưa ra ví dụ bằng cách sử dụng Clojure dưới đây:
Nếu bạn có thể viết một add
hàm trong Clojure (defn add [a b] ...your-implementation-here... )
, bạn có thể đặt tên +
như vậy (defn + [a b] ...your-implementation-here... )
. Trên thực tế đây là những gì được thực hiện trong triển khai thực tế (phần thân của hàm có liên quan nhiều hơn một chút nhưng định nghĩa về cơ bản giống như tôi đã viết ở trên).
Còn ký hiệu infix thì sao? Vâng Clojure sử dụng prefix
ký hiệu (hoặc tiếng Ba Lan), vì vậy chúng ta có thể tạo một infix-to-prefix
macro có thể biến mã tiền tố thành mã Clojure. Điều này thực sự dễ dàng đáng ngạc nhiên (nó thực sự là một trong những bài tập vĩ mô trong công án clojure)! Nó cũng có thể được nhìn thấy trong tự nhiên, ví dụ, xem macro Incanter$=
.
Đây là phiên bản đơn giản nhất từ công án giải thích:
(defmacro infix [form]
(list (second form) (first form) (nth form 2)))
;; takes a form (ie. some code) as parameter
;; and returns a list (ie. some other code)
;; where the first element is the second element from the original form
;; and the second element is the first element from the original form
;; and the third element is the third element from the original form (indexes start at 0)
;; example :
;; (infix (9 + 1))
;; will become (+ 9 1) which is valid Clojure code and will be executed to give 10 as a result
Để thúc đẩy điểm hơn nữa, một số trích dẫn Lisp :
Một phần của những gì làm cho Lisp đặc biệt là nó được thiết kế để phát triển. Bạn có thể sử dụng Lisp để xác định toán tử Lisp mới. Khi các khái niệm trừu tượng mới trở nên phổ biến (ví dụ lập trình hướng đối tượng), nó luôn trở nên dễ thực hiện chúng trong Lisp. Giống như DNA, một ngôn ngữ như vậy không lỗi thời.
- Paul Graham, Lisp thường gặp
Lập trình tại khu vực Lisp giống như chơi với các lực lượng nguyên thủy của vũ trụ. Nó cảm thấy như sét giữa các ngón tay của bạn. Không có ngôn ngữ nào khác thậm chí cảm thấy gần gũi.
- Glenn Ehrlich, Đường đến Lisp