Как "+" реализован в Common Lisp с использованием специальных операторов / форм - PullRequest
0 голосов
/ 01 мая 2018

В На Лиспе (стр. 9) можно найти следующую заявку:

Функции являются строительными блоками программ на Лиспе. Они также являются строительными блоками Лисп. В большинстве языков оператор + - это нечто совершенно другое из пользовательских функций. Но у Лиспа есть одна модель, функция приложения, чтобы опишите все вычисления, выполненные программой. Оператор Lisp + является функцией, как те, которые вы можете определить сами. На самом деле, за исключением небольшого числа операторов, называемых специальными формами, ядро Lisp представляет собой набор функций Lisp. Что мешает вам добавить к этому коллекция? Ничего общего: если вы думаете о чем-то, что Лисп может сделать, вы можете написать это самостоятельно, и ваша новая функция будет обрабатываться так же, как встроенная из них.

У меня вопрос, как именно можно реализовать оператор типа +, используя следующие специальные операторы? Или же на самом деле используется больше операторов, а Грэм просто неточен и драматичен?

block      let*                  return-from      
catch      load-time-value       setq             
eval-when  locally               symbol-macrolet  
flet       macrolet              tagbody          
function   multiple-value-call   the              
go         multiple-value-prog1  throw            
if         progn                 unwind-protect   
labels     progv                                  
let        quote    

Есть ли способ увидеть исходный код для этих функций?

Ответы [ 5 ]

0 голосов
/ 03 мая 2018

На другом языке, поскольку Algol является наиболее распространенным, а APL, возможно, является наиболее очевидным, создание пользовательских абстракций, которые неотличимы от функций и форм, с которыми поставляется язык, является совершенно особенным.

Таким образом, я думаю, что вы неправильно прочитали текст. Представьте, что вы хотите создать числовую библиотеку, которая расширяет языковую концепцию чисел, возможно, интервалами. Вы создаете библиотеку и определяете способ создания интервалов и заставляете свою библиотеку работать по числу и интервалам. Если бы у вас была библиотека, которая занималась математикой, вы могли бы просто использовать свой класс в библиотеке, и он работал бы из коробки с интервалами, учитывая, что вы определили все необходимые функции. Сейчас в большинстве языков Algol +, /, ... не являются функциями, а являются операторами, и у них есть специальные правила, поэтому, хотя C ++ сделал перегрузку операторов, не во многих других языках есть поддержка для создания +, который работает с вашим новый тип интервала. Решением будут функции, которые явно не будут выглядеть как собственные примитивы языка, поскольку они являются операторами. В APL у всех примитивов есть специальные символы, а у всех определенных пользователем нет, поэтому все пользовательские абстракции легко увидеть, поскольку они не являются причудливыми символами.

Сегодня мы довольно часто выпускаем новые версии Java, JavaScript, C ++ и т. Д. Это необходимо, поскольку у этих языков нет способа абстрагироваться от собственного синтаксиса в языке. В JavaScript сегодня есть babel, который в основном дает вам метод переноса одного синтаксиса в другой, но ему еще предстоит реализовать функцию, которая позволяет вам делать это из языка. Это то, что было в Лиспе на протяжении нескольких десятилетий, и современные языки получают функции для бодрости, но некоторые все еще редки.

Я создал язык для шуток, у которого было такое же отсутствие цифр, как и для первого шурупа, так как он меня не интересовал. Я также должен был сделать 99 бутылок пива на этом языке. Я использовал списки и символы и создал и определил +, -, zerop. и когда вы смотрите на реальную программу, вы не видите, что ей не хватает цифр.

Мне нравится выступление Гая Л. Стила из 98 о расширении языков программирования . Он является первоначальным автором Scheme и принимал участие во многих языках, включая Java и Common Lisp.

0 голосов
/ 01 мая 2018

cl:+ просто ведет себя как функция и обрабатывается как функция.

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

Common Lisp имеет три типа операторов: функции , макросы и специальные операторы .

Стандарт мало говорит о том, как они реализованы. Есть основания полагать, что реализация Common Lisp будет иметь дополнительные внутренние операторы, используемые для реализации стандартных.

  • Существует фиксированное количество специальных операторов - хотя реализация CL может предусматривать дополнительные специальные операторы. Специальные операторы не являются функциями, и пользователь не может определять специальные операторы.

  • CL определяет набор стандартных макросов и способы определения пользователем новых макросов. Как определяются стандартные макросы, не указано.

  • CL определяет набор стандартных функций и способы определения пользователем новых функций. Как определяются стандартные функции, не указано.

0 голосов
/ 01 мая 2018

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

Он говорит + (как и любая другая функция) - это функция :

  • Его можно вызвать с использованием обычного синтаксиса (+ x y z) (где + - функция, а x, y, z аргументы).
  • Аргументы будут оцениваться первыми: (f (g) (h)) вызовет оба g и h перед вызовом f, даже если f окажется +.
  • Вы можете передавать его как любую другую функцию и вызывать через funcall, а apply: (let ((x #'+)) (funcall x 1 2 3)) равно 6.

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

Конечно, это все еще оставляет дверь открытой для "магии компилятора". В какой-то момент + должен выполнить операции низкого уровня, которые зависят, например, от о том, как числа реализованы. Детали будут отличаться в зависимости от вашего компилятора Lisp.

0 голосов
/ 01 мая 2018

На практическом уровне вы правы, отметив, что не очень эффективно реализовать +, используя только основные специальные формы, без каких-либо арифметических низкоуровневых утилит (поскольку процессоры, как правило, очень хорошо по арифметике).

Суть Грэма, я полагаю, заключается в том, что в Common Lisp нет ничего присущего функции +, которая помешала бы вам определить ее самостоятельно. В большинстве языков (C ++ является еще одним исключением), + будет реализован принципиально иным образом, чем пользовательские функции. Две распространенные причины: + обычно использует инфиксную нотацию, тогда как вызовы функций используют func(arg1, arg2) нотацию; и обычно невозможно определить новые пользовательские функции, используя случайные символы, такие как знак плюс.

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

Например, это прекрасно работает (с предупреждением) в GNU clisp, тогда как не было бы возможности сделать то же самое, скажем, в JavaScript:

(defun + (a b) (- a (- 0 b))) ; using '- to avoid having to look up other forms
0 голосов
/ 01 мая 2018

Вот источник из sbcl в src / code / numbers.lisp

(macrolet ((define-arith (op init doc)
             `(defun ,op (&rest numbers)
                (declare (explicit-check))
                ,doc
                (if numbers
                    (let ((result (the number (fast-&rest-nth 0 numbers))))
                      (do-rest-arg ((n) numbers 1 result)
                        (setq result (,op result n))))
                    ,init))))
  (define-arith + 0
    "Return the sum of its arguments. With no args, returns 0.")
  (define-arith * 1
    "Return the product of its arguments. With no args, returns 1."))
...