Что такое символ в lisp / схеме?
Для любви всемогущего мне еще предстоит понять цель символа 'iamasymbol
. Я понимаю числа, булевы, строки … переменные. Но символы слишком велики для моего маленького императивного мышления. Для чего я их использую? Как они должны использоваться в программе? Мое понимание этой концепции просто терпит неудачу.
В Scheme и Racket символ похож на неизменяемую строку, которая оказывается интернированной, так что символы можно сравнить с eq?
(быстрое, по существу сравнение указателей). Символы и строки – это отдельные типы данных.
Одно использование символов – это легкие enums. Например, можно сказать, что направление – это 'north
, 'south
, 'east
или 'west
. Разумеется, вы можете использовать строки с той же целью, но это будет немного менее эффективно. Использование чисел было бы плохой идеей; представлять информацию в максимально очевидной и прозрачной форме.
В другом примере SXML представляет собой представление XML с использованием списков, символов и строк. В частности, строки представляют символьные данные, а символы представляют собой имена элементов. Таким образом, XML hello world
будет представлен значением (list 'em "hello world")
, которое может быть более компактно записано '(em "hello world")
.
Другое использование символов – это ключи. Например, вы можете реализовать таблицу методов в качестве символов отображения словаря для функций реализации. Чтобы вызвать метод, вы просматриваете символ, соответствующий имени метода. Lisp / Scheme / Racket делает это очень просто, потому что язык уже имеет встроенное соответствие между идентификаторами (часть синтаксиса языка) и символами (значениями на языке). Эта переписка упрощает поддержку макросов , которые реализуют пользовательские синтаксические расширения для языка. Например, можно реализовать систему classов в виде библиотеки макросов, используя неявное соответствие между «именами методов» (синтаксическое понятие, определяемое системой classов) и символами:
(send obj meth arg1 arg2) => (apply (lookup-method obj 'meth) obj (list arg1 arg2))
(В других Lisp, я сказал, что в основном это правда, но есть дополнительные вещи, о которых нужно знать, например, пакеты и функции с переменными слотами, IIRC.)
Символ – это объект с простым строковым представлением, в котором (по умолчанию) гарантируется интернирование ; т.е. любые два символа, которые записаны одинаково, являются одним и тем же объектом в памяти (ссылочное равенство).
Почему у Лисса есть символы? Ну, это в значительной степени артефакт того, что Lisps встроили свой собственный синтаксис в качестве типа данных языка. Компиляторы и интерпретаторы используют символы для представления идентификаторов в программе; поскольку Lisp позволяет вам представлять синтаксис программы как данные, он предоставляет символы, потому что они являются частью представления.
Что они полезны помимо этого? Ну, несколько вещей:
- Lisp обычно используется для реализации встроенных доменных языков. Многие из методов, используемых для этого, происходят из мира компилятора, поэтому символы здесь полезны.
- Макросы в Common Lisp обычно include обработку символов более подробно, чем дает этот ответ. (Хотя, в частности, генерация уникальных идентификаторов для расширений макросов требует наличия символа, который гарантированно никогда не будет равным любому другому.)
- Исправленные типы enums лучше реализуются как символы, чем строки, потому что символы могут сравниваться по эталонному равенству.
- Существует много структур данных, которые вы можете построить, где вы можете получить выгоду от использования символов и ссылочного равенства.
Символы в lisp являются человекочитаемыми идентификаторами. Все они одиночные. Поэтому, если вы объявите «foo где-то в вашем коде, а затем снова используйте« foo », он будет указывать на то же место в памяти.
Пример использования: разные символы могут представлять разные фигуры на шахматной доске.
Символ – это просто специальное имя для значения. Значение может быть любым, но этот символ используется для обозначения одного и того же значения каждый раз, и такого рода вещи используются для быстрого сравнения. Как вы говорите, вы сообразительны, они похожи на числовые константы в C, и так они обычно реализуются (внутренне сохраненные числа).
Из структуры и интерпретации компьютерных программ Второе издание Гарольда Абельсона и Джеральда Джей Суссмана 1996:
Чтобы манипулировать символами, нам нужен новый элемент нашего языка: возможность процитировать объект данных. Предположим, что мы хотим построить список (ab). Мы не можем выполнить это с помощью (list ab), потому что это выражение строит список значений a и b, а не самих символов. Эта проблема хорошо известна в контексте естественных языков, где слова и предложения можно рассматривать либо как семантические сущности, либо как символьные строки (синтаксические сущности). Общей практикой в естественных языках является использование кавычек, указывающих на то, что слово или предложение следует трактовать буквально в виде строки символов. Например, первая буква «Джона» явно «Дж.». Если мы скажем кому-то «произнести свое имя вслух», мы ожидаем услышать имя этого человека. Однако, если мы скажем кому-то «произнести» ваше имя «вслух», мы ожидаем услышать слова «ваше имя». Обратите внимание, что мы вынуждены вставлять кавычки, чтобы описать то, что кто-то может сказать. Мы можем следовать этой же практике для определения списков и символов, которые должны рассматриваться как объекты данных, а не как выражения для оценки. Однако наш формат цитирования отличается от формата естественных языков тем, что мы помещаем кавычку (традиционно, символ одиночной кавычки) только в начале объекта, который должен быть процитирован. Мы можем избежать этого в синтаксисе Scheme, потому что мы полагаемся на пробелы и круглые скобки для разграничения объектов. Таким образом, значение символа одиночной кавычки означает процитировать следующий объект. Теперь мы можем различать символы и их значения:
(define a 1) (define b 2) (list ab) (1 2) (list 'a 'b) (ab) (list 'ab) (a 2)
Списки, содержащие символы, могут выглядеть так же, как выражения нашего языка:
(* (+ 23 45) (+ x 9)) (define (fact n) (if (= n 1) 1 (* n (fact (- n 1)))))
Пример: Символическая дифференциация