Існує багато мов, які дозволяють проводити якесь метапрограмування . Зокрема, я здивований, не бачачи жодної відповіді, яка б говорила про сім'ю мов Лісп .
З Вікіпедії:
Метапрограмування - це написання комп’ютерних програм з можливістю трактувати програми як їх дані.
Пізніше в тексті:
Лісп - це, мабуть, квінтесенціальна мова із засобами метапрограмування, як через його історичний пріоритет, так і через простоту та силу його метапрограмування.
Мови Lisp
Зрозумілий короткий вступ до Lisp випливає.
Один із способів побачити код - це набір інструкцій: зробіть це, потім зробіть це, потім зробіть це інше ... Це список! Перелік речей, які потрібно виконати програмою. І звичайно, ви можете мати списки всередині списків, щоб представляти петлі тощо.
Якщо ми представимо список , що містить елементи а, Ь, с, d , як це: (ABCD) , ми отримуємо те , що виглядає як виклик функції Лиспа, де a
є функція, і b
, c
, d
є аргументи. Насправді типовий "Hello Hello!" програма може бути написана так:(println "Hello World!")
Звичайно b
, c
чи d
можуть бути списки, які також оцінюють щось. Наступне: (println "I can add :" (+ 1 3) )
буде надрукувати "" Я можу додати: 4 ".
Отже, програма - це серія вкладених списків, а перший елемент - функція. Хороша новина - ми можемо маніпулювати списками! Тож ми можемо маніпулювати мовами програмування.
Перевага Lisp
Lisps - це не стільки мови програмування, скільки інструментарій для створення мов програмування. Програмована мова програмування.
У Lisps це не тільки набагато простіше зробити нових операторів, але навіть неможливо написати деякі оператори іншими мовами, оскільки аргументи оцінюються при передачі функції.
Наприклад, мовою, схожою на C, скажімо, що ви хочете написати if
оператора самостійно, щось на зразок:
my-if(condition, if-true, if-false)
my-if(false, print("I should not be printed"), print("I should be printed"))
У цьому випадку обидва аргументи будуть оцінені та надруковані у порядку, залежному від порядку оцінки аргументів.
У Lisps написання оператора (ми називаємо це макросом) та написання функції - це приблизно одне й те саме і використовується однаково. Основна різниця полягає в тому, що параметри макросу не оцінюються перед тим, як передаватися як аргументи макросу. Це важливо, щоб мати можливість записувати деякі оператори, як if
вище.
Мови реального світу
Покажіть, як саме тут трохи поза сферою, але я радимо спробувати програмування в одному Lisp, щоб дізнатися більше. Наприклад, ви можете подивитися:
- Схема , старий, досить «чистий» Лісп з невеликим стрижнем
- Загальний Lisp, більший Lisp з добре інтегрованою об'єктною системою та багатьма реалізаціями (це стандартизована ANSI)
- Ракетка набрала Lisp
- Clojure мій улюблений, наведеними вище прикладами був код Clojure. Сучасний Lisp, що працює на JVM. Існує кілька прикладів макросів Clojure і на SO (але це не правильне місце для початку. Я спершу поглянув би на 4clojure , braveclojure або clojure koans )).
О, і до речі, Lisp означає LISt Processing.
Щодо ваших прикладів
Я надам приклади, використовуючи Clojure нижче:
Якщо ви можете написати add
функцію в Clojure (defn add [a b] ...your-implementation-here... )
, ви можете назвати її +
так (defn + [a b] ...your-implementation-here... )
. Це насправді те, що робиться в реальній реалізації (частина функції трохи більше задіяна, але визначення по суті таке, як я писав вище).
Що з інфікцією позначень? Ну Clojure використовує prefix
(або польську) позначення, тому ми могли б зробити infix-to-prefix
макрос, який перетворив би префіксний код у код Clojure. Що насправді напрочуд просто (це насправді одна з макро-вправ у кожурних коанах)! Його також можна побачити в дикій природі, наприклад, див. Макрос Incanter$=
.
Ось найпростіша версія з пояснень:
(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
Щоб ще більше підбити крапку, деякі цитати Lisp :
«Частина того, що робить Лісп відмітним, - це те, що він створений для розвитку. Ви можете використовувати Lisp для визначення нових операторів Lisp. Оскільки нові абстракції стають популярними (наприклад, об’єктно-орієнтоване програмування), завжди виявляється легко реалізувати їх у Lisp. Як і ДНК, така мова не виходить зі стилю ».
- Пол Грехем, ANSI Common Lisp
«Програмування в Ліспі - це як гра з первісними силами Всесвіту. Відчувається блискавка між кінчиками пальців. Жодна інша мова навіть не відчуває себе близько.
- Гленн Ерліх, Дорога до Ліспа