Отдельные пространства имен для функций и переменных в Common Lisp и Scheme

Схема использует единое пространство имен для всех переменных, независимо от того, связаны ли они с функциями или другими типами значений. Common Lisp разделяет их так, что идентификатор "hello" может ссылаться на функцию в одном контексте и строку в другом.

(Примечание 1: Этот вопрос нуждается в примере из приведенного выше; не стесняйтесь редактировать его и добавлять один, или отправьте по электронной почте оригинальному автору с ним, и я сделаю это.)

Однако в некоторых контекстах, таких как передача функций в качестве параметров другим функциям, программист должен явно различать, что он указывает переменную функции, а не переменную не функции, используя #', как в:

(сортировка (список '(9 A) '(3 B) '(4 C)) #'<: key # 'сначала) 

Я всегда считал это чем-то вроде бородавки, но недавно я столкнулся с аргументом, что это на самом деле особенность:

... важное различие на самом деле заключается в синтаксисе форм, а не в типе объектов. Не зная ничего о задействованных значениях времени выполнения, совершенно ясно, что первый элемент формы функции должен быть функцией. CL принимает этот факт и делает его частью языка, наряду с макро и специальными формами, которые также могут (и должны) быть определены статически. Итак, мой вопрос: почему вы хотите, чтобы имена функций и имена переменных находились в одном и том же пространстве имен, когда основное использование имен функций должно появиться там, где имя переменной редко будет появляться?
Рассмотрим случай с именами классов: почему класс с именем FOO должен предотвращать использование переменных с именем FOO? Единственный раз, когда я буду ссылаться на класс по имени FOO, это контексты, которые ожидают имя класса. Если в редких случаях мне нужно получить объект класса, который связан с именем класса FOO, существует FIND-CLASS.

Этот аргумент имеет некоторый смысл для меня из опыта; в Haskell есть аналогичный случай с именами полей, которые также являются функциями, используемыми для доступа к полям. Это немного неловко

data Point = Point { x, y :: Double {- lots of other fields as well --} }
isOrigin p = (x p == 0) && (y p == 0)

Это решается небольшим дополнительным синтаксисом, который особенно хорош NamedFieldPuns расширение:

isOrigin2 Point{x,y} = (x == 0) && (y == 0)

Итак, к вопросу, помимо согласованности, каковы преимущества и недостатки как для Common Lisp, так и для Scheme, и в целом, единого пространства имен для всех значений по сравнению с отдельными для функций и не-значений функций?

6 ответов

Решение

Два разных подхода имеют имена: Lisp-1 и Lisp-2. Lisp-1 имеет единое пространство имен для переменных и функций (как в схеме), а Lisp-2 имеет отдельные пространства имен для переменных и функций (как в Common Lisp). Я упоминаю об этом, потому что вы можете не знать о терминологии, поскольку вы не обращались к ней в своем вопросе.

Википедия относится к этой дискуссии:

Является ли отдельное пространство имен для функций преимуществом, является источником спора в сообществе Lisp. Это обычно упоминается как дебаты Lisp-1 против Lisp-2. Lisp-1 относится к модели Scheme, а Lisp-2 относится к модели Common Lisp. Эти имена были придуманы в статье 1988 года Ричарда П. Габриэля и Кента Питмана, в которой подробно сравниваются два подхода.

В статье Габриэля и Питмана под названием " Технические проблемы разделения функциональных ячеек и стоимостных ячеек" рассматривается именно эта проблема.

На самом деле, как изложено в статье Ричарда Габриэля и Кента Питмана, спор идет о Lisp-5 против Lisp-6, поскольку там уже есть несколько других пространств имен, в статье упоминаются имена типов, имена тегов, имена блоков и имена деклараций. edit: это кажется неправильным, как указывает Райнер в комментарии: Схема на самом деле выглядит как Lisp-1. Однако эта ошибка в основном не затронута.

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

Я знаю, что сторонникам Lisp-5 нравится тот факт, что функции - это данные, и это выражается в ядре языка. Мне нравится тот факт, что я могу назвать список "list", а автомобиль - "car", не путая мой компилятор, и функции в любом случае являются принципиально особым видом данных. редактировать: это моя главная мысль: отдельные пространства имен вовсе не бородавка.

Мне также понравилось то, что Паскаль Констанца сказал по этому поводу.

Имя функции в Scheme - это просто переменная с функцией в качестве значения. Делаю ли я (define x (y) (z y)) или же (let ((x (lambda (y) (z y))))Я определяю функцию, которую могу вызвать. Таким образом, идея о том, что "имя переменной будет редко появляться там", является довольно призрачной для Схемы.

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

Я встречал подобное различие в Python (унифицированное пространство имен) и Ruby (отдельные пространства имен для методов против не-методов). В этом контексте я предпочитаю подход Python - например, с этим подходом, если я хочу составить список вещей, некоторые из которых являются функциями, а другие нет, мне не нужно делать ничего другого с их именами например, в зависимости от их "функциональности". Аналогичные соображения применимы ко всем случаям, когда функциональные объекты должны группироваться, а не вызываться (аргументы и возвращаемые значения из функций высшего порядка и т. Д. И т. Д.).

Не-функции также могут быть вызваны (если их классы определяют __call__в случае Python - особый случай "перегрузки операторов"), поэтому "контекстное различие" также не обязательно ясно.

Тем не менее, мой опыт "lisp-oid" в основном был связан со Scheme, а не с Common Lisp, так что я могу быть подсознательно предвзятым из-за знакомства с единым пространством имен, которое в итоге приходит из этого опыта.

Самым большим недостатком, который я вижу, по крайней мере для Common Lisp, является понятность. Мы все можем согласиться с тем, что он использует разные пространства имен для переменных и функций, но сколько у него? В PAIP Norvig показал, что у него есть "как минимум семь" пространств имен.

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

Мне удобно использовать один и тот же символ для переменной и для функции, но в более непонятных областях я прибегаю к использованию разных имен из-за страха (сталкивающиеся пространства имен могут быть очень сложными для отладки!), И это действительно никогда не должно быть дело.

Есть хорошие вещи для обоих подходов. Тем не менее, я считаю, что когда это имеет значение, я предпочитаю иметь как функцию LIST, так и переменную LIST, чем неправильно писать одну из них.

Другие вопросы по тегам