Идея REPL исходит от сообщества Lisp.Существуют и другие формы текстовых интерактивных интерфейсов, например, интерфейс командной строки .Некоторые текстовые интерфейсы также позволяют выполнять подмножество некоторого языка программирования.
REPL означает READ EVAL PRINT LOOP: (loop (print (eval (read)))).
Каждая из четырех вышеперечисленных функций является примитивными функциями Lisp.
В Lisp REPL не является интерпретатором командной строки (CLI).READ
не читает команды, а REPL не выполняет команды.READ
читает входные данные в формате s-выражения и преобразует их во внутренние данные.Таким образом, функция READ
может читать все виды s-выражений - не только код Lisp.
READ читает s-выражение. Это формат данных, который также поддерживает источник кодированиякод.READ возвращает данные Lisp.
EVAL принимает исходный код Lisp в виде данных Lisp и оценивает его. Могут возникнуть побочные эффекты, а EVAL возвращает одно или несколько значений.Как реализуется EVAL с помощью интерпретатора или компилятора, не определено.Реализации используют разные стратегии.
PRINT берет данные Lisp и печатает их в выходной поток в виде s-выражений.
LOOP просто зацикливается на этом.В реальной жизни REPL является более сложным и включает обработку ошибок и подциклы, так называемые разрывные циклы.В случае ошибки можно получить еще один REPL с добавленными командами отладки в контексте ошибки.Значение, полученное в одной итерации, также может быть повторно использовано в качестве входных данных для следующей оценки.
Поскольку в Lisp используются как код-как-данные, так и функциональные элементы, есть небольшие отличия от других языков программирования.
Языки, которые похожи, будут предоставлять аналогичные интерактивные интерфейсы.Например, Smalltalk также допускает интерактивное выполнение, но он не использует формат данных для ввода-вывода, как это делает Lisp.То же самое для любого интерактивного интерфейса Ruby / Python / ....
Вопрос:
Итак, насколько важна первоначальная идея ЧТЕНИЯ ВЫРАЖЕНИЙ, ОЦЕНКИ их и ПЕЧАТИ их значений?Это важно по отношению к тому, что делают другие языки: чтение текста, его синтаксический анализ, выполнение, при желании что-то напечатать и, возможно, печать возвращаемого значения?Часто возвращаемое значение на самом деле не используется.
Таким образом, есть два возможных ответа :
Lisp REPL отличается от большинства других текстовых интерактивных интерфейсов, потому что он основан на идееввода-вывода данных s-выражений и их оценки.
a REPL - это общий термин, описывающий текстовые интерактивные интерфейсы для реализаций языка программирования или их подмножеств.
REPL в Lisp
В реальных реализациях Lisp REPL имеют сложную реализацию и предоставляют множество услуг, вплоть до интерактивных презентаций (Symbolics,CLIM, SLIME) объектов ввода и вывода.Расширенные реализации REPL доступны, например, в SLIME (популярной интегрированной среде разработки для Emacs для Common Lisp), McCLIM, LispWorks и Allegro CL .
Пример взаимодействия Lisp REPL :
список продуктов и цен:
CL-USER 1 > (setf *products* '((shoe (100 euro))
(shirt (20 euro))
(cap (10 euro))))
((SHOE (100 EURO)) (SHIRT (20 EURO)) (CAP (10 EURO)))
заказ, список продуктов и количество:
CL-USER 2 > '((3 shoe) (4 cap))
((3 SHOE) (4 CAP))
Цена заказа, *
- это переменная, содержащая последнее значение REPL.Оно не содержит это значение в виде строки, но содержит реальные фактические данные.
CL-USER 3 > (loop for (n product) in *
sum (* n (first (second (find product *products*
:key 'first)))))
340
Но вы также можете вычислить код на Лиспе:
Давайте возьмем функцию, которая добавляет квадраты своих двухargs:
CL-USER 4 > '(defun foo (a b) (+ (* a a) (* b b)))
(DEFUN FOO (A B) (+ (* A A) (* B B)))
Четвертый элемент - это просто арифметическое выражение.*
относится к последнему значению:
CL-USER 5 > (fourth *)
(+ (* A A) (* B B))
Теперь мы добавим вокруг него код, чтобы связать переменные a
и b
с некоторыми числами.Мы используем функцию Lisp LIST
для создания нового списка.
CL-USER 6 > (list 'let '((a 12) (b 10)) *)
(LET ((A 12) (B 10)) (+ (* A A) (* B B)))
Затем мы оцениваем вышеприведенное выражение. Опять же, *
относится к последнему значению.
CL-USER 7 > (eval *)
244
Существует несколько переменных, которые обновляются при каждом взаимодействии REPL
. Примерами являются *
, **
и ***
для предыдущих значений. Также есть +
для предыдущего ввода. Эти переменные имеют в качестве значений не строки, а объекты данных. +
будет содержать последний результат операции чтения REPL. Пример:
Каково значение переменной *print-length*
?
CL-USER 8 > *print-length*
NIL
Посмотрим, как список читается и печатается:
CL-USER 9 > '(1 2 3 4 5)
(1 2 3 4 5)
Теперь давайте установим вышеуказанный символ *print-length*
в 3. ++
относится ко второму предыдущему прочитанному вводу, как к данным. SET
устанавливает значение символа.
CL-USER 10 > (set ++ 3)
3
Тогда вышеприведенный список печатается по-другому. **
относится ко второму предыдущему результату - данные, а не текст.
CL-USER 11 > **
(1 2 3 ...)