Подтвердить что ты не робот

В Lisp код - это данные. Какая польза от этого?

В Lisp любой программный код фактически является действительной структурой данных. Например, это добавляет один и два вместе, но также список из трех элементов.

(+ 1 2)

Какая польза от этого? Что это делает вас невозможным и/или менее элегантным на других языках?

4b9b3361

Ответ 1

Чтобы сделать вещи немного более четкими в отношении представления кода, учтите, что в каждом коде языка есть данные: все, что вам нужно, это строки. (И, возможно, несколько операций с файлами.) Созерцая, как это поможет вам подражать преимуществам Lisp наличия макросистемы, является хорошим способом просветления. Еще лучше, если вы попытаетесь реализовать такую ​​макросистему. Вы столкнетесь с преимуществами структурированного представления и плоскостности строк, необходимости сначала выполнить преобразования и определить "синтаксические крючки", чтобы указать, где их применять, и т.д.

Но главное, что вы увидите во всем этом, заключается в том, что макросы - это, по сути, удобное средство для перехватчиков компилятора - те, которые подключены к вновь созданным ключевым словам. Таким образом, единственное, что действительно необходимо, - это некоторый способ взаимодействия кода пользователя с кодом компилятора. Плоские строки - один из способов сделать это, но они предоставляют так мало информации о том, что макро-писателю остается задача реализовать парсер с нуля. С другой стороны, вы можете выявить некоторую внутреннюю структуру компилятора, такую ​​как предварительно обработанные деревья AST, но они, как правило, предоставляют слишком много информации, чтобы быть удобной, и это означает, что компилятор должен как-то разбираться в новом синтаксическом расширении, которое вы намерены реализовать. S-выражения являются хорошим решением для последнего: компилятор может анализировать все, поскольку синтаксис является единообразным. Они также являются решением для первого, поскольку они простые структуры с богатой поддержкой языка для их разделения и повторного объединения их по-новому.

Но, конечно, это не конец истории. Например, интересно сравнить простые символические макросы, как в CL, и гигиенические макросы, как и в реализациях Схемы: они обычно реализуются путем добавления дополнительной информации к представленным данным, а это означает, что вы можете делать больше с помощью этих макросистем. (Вы также можете сделать больше с макросами CL, поскольку дополнительная информация также доступна, но вместо того, чтобы сделать ее частью представления синтаксиса, она передавалась как дополнительный аргумент среды макросам.)

Ответ 2

Мой любимый пример... В колледже некоторые мои друзья писали компилятор в Lisp. Таким образом, все их структуры данных, включая дерево разбора, были lisp s-выражениями. Когда пришло время реализовать фазу генерации кода, они просто выполнили свое дерево синтаксического разбора.

Ответ 3

Lisp был разработан для манипуляции символическими данными всех видов. Оказывается, можно также увидеть любую программу Lisp в качестве символических данных. Таким образом, вы можете применить возможности манипуляции Lisp к себе.

Если вы хотите вычислить программы (для создания новых программ, для компиляции программ для машинного кода, для перевода программ из Lisp на другие языки), у вас есть в основном три варианта:

  • используйте строки. Это становится утомительным разбором и неразборчивыми строками все время.

  • используйте деревья синтаксического разбора. Полезно, но становится сложным.

  • используйте символические выражения, например, в Lisp. Программы подготавливаются к знакомым структурам данных (спискам, символам, строкам, номерам и т.д.), А процедуры манипуляции записываются в обычной функциональности, предоставляемой языком.

Итак, что вы получаете с Lisp? Относительно простой способ писать программы, которые управляют другими программами. От макросов до компиляторов есть много примеров этого. Вы также можете легко вставлять языки в Lisp.

Ответ 4

Он позволяет вам писать макросы, которые просто преобразуют одно дерево списков в другое. Простой пример (схема):

(define-syntax and
  (syntax-rules ()
   ((and) #t)
   ((and thing) thing)
   ((and thing rest ...) (if thing (and rest ...) #f))))

Обратите внимание, что макро-вызовы просто сопоставляются с предложениями (and), (and thing) и (and thing rest ...) (в зависимости от арности вызова) и обрабатываются соответствующим образом.

С другими языками макросы должны иметь дело с каким-то внутренним АСТ преобразуемого кода --- иначе не было бы простого способа "видеть" ваш код в программном формате --- и что увеличит трение написания макросов.

В программах Lisp макросы обычно используются довольно часто, именно из-за низкого трения их написания.