В чем смысл конструктивного решения иметь отдельные пространства имен для значений и функций в Common Lisp? Каковы аргументы и против?
Почему несколько пространств имен?
Ответ 1
Общий Lisp является в основном потомком от первоначального Lisp 1.5, или, скорее, унификации его расходящихся диалектов. Первоначальный Lisp 1.5 был тем, что в настоящее время называется Lisp -2. Потому что это было в шестидесятые годы, и тот факт, что вы могли передавать функции другим функциям, был довольно странным. Никто даже не подумал бы позволить им использовать одно и то же пространство имен. Почти любой язык, изобретенный сегодня с поддержкой функций более высокого порядка и анонимных функций, выбирает подход с одним пространством имен. Включая Clojure, который в противном случае ближе к Common Lisp, чем к схеме.
Схема, такая как Clojure, первоначально не была расходящимся диалектом от Lisp 1.5, и для их целей имеет смысл.
Конечно, в Clojure, векторах, хэш-картах, множествах и все, что также может быть применено к аргументам, поэтому в некотором смысле вектор в Clojure можно рассматривать как функцию, которая принимает натуральное число и производит значение от этого.
Ответ 2
См. статью Ричарда П. Габриэля Технические вопросы разделения в функциональных ячейках и ячейках значений для полной академической обработки этого предмета.
Ответ 3
Хотя в теории может быть много аргументов, я бы поспорил, что он в основном философский по происхождению. Scheme, a Lisp -1, предпочитает элегантность по сравнению с практичностью и выбирает тот же синтаксис define
для переменных и функций, что делает одно пространство имен естественным (и поощряет функциональный стиль программирования). Общий Lisp имеет тенденцию отдавать предпочтение практичности и власти над элегантностью и был попыткой построения консенсуса, поэтому, увидев существующее решение с двумя именами, широко принятое и хорошо работающее, приняло его.
Однако на практике это в основном означает три вещи:
- В Common Lisp (и других Lisp -2's) вам нужно использовать
funcall
много - В схеме (и других Lisp -1) вы должны быть осторожны, чтобы не переопределять
необходимые имена функций с переменными; например аргументы функции
lst
вместоlist
- В Интернете будут аргументы
Это один из основных факторов в том, почему некоторые люди предпочитают один Lisp другому.
Ответ 4
Мне действительно нравится иметь несколько пространств имен (более двух четных); это упрощает работу пользователя и компилятора (реализации):
CL-USER> (defclass test () ())
#<STANDARD-CLASS TEST>
CL-USER> (defun test ())
TEST
CL-USER> (defparameter test 42)
TEST
CL-USER> (describe 'test)
COMMON-LISP-USER::TEST
[symbol]
TEST names a special variable:
Value: 42
TEST names a compiled function:
Lambda-list: ()
Derived type: (FUNCTION NIL (VALUES NULL &OPTIONAL))
Source form:
(LAMBDA ()
(DECLARE (MUFFLE-CONDITIONS COMPILER-NOTE))
(PROGN
(SB-INT:NAMED-LAMBDA TEST
NIL
(BLOCK TEST))))
TEST names the standard-class #<STANDARD-CLASS TEST>:
Direct superclasses: STANDARD-OBJECT
No subclasses.
Not yet finalized.
No direct slots.
; No value
CL-USER> (make-instance 'test)
#<TEST {1005B1D601}>
CL-USER> (test)
NIL
CL-USER> test
42
CL-USER>
Ответ 5
В дополнение к другим проблемам, упомянутым выше, наличие отдельного пространства имен для функций делает CL негигиеничные макросы гораздо менее вероятными, чтобы укусить пользователя макроса. В CL имя, связанное в точке вызова, которое появляется в расширении макроса, будет иметь определение, используемое в вызывающей точке, а не определение, используемое там, где определяется макрос. Таким образом, в версии CL1 Lisp -1, если макрос расширяется до вызова функции LIST, а LIST определяются как переменная в точке, где был вызван макрос, макрос будет работать неправильно. (Обратите внимание, что gensyms не решают эту проблему, в отличие от обратной задачи, которую они решают.)
Это не происходит в Схеме, потому что по умолчанию макросы Scheme являются гигиеничными: все имена, используемые при расширении макроса, имеют значения, которые они имели там, где определяется макрос, а не где он используется.