Что именно является символом в lisp/ схеме?

Ради любви всемогущего, мне еще предстоит понять цель символа 'iamasymbol, Я понимаю числа, логические значения, строки... переменные. Но символы - это слишком много для моего маленького ума, требующего императивного мышления. Для чего именно я их использую? Как они должны использоваться в программе? Мое понимание этой концепции просто неудачно.

6 ответов

Решение

В схеме и ракетке символ похож на неизменную строку, которая оказывается интернированной, так что символы можно сравнивать с eq? (быстрое, по сути, сравнение указателей). Символы и строки являются отдельными типами данных.

Одно использование для символов - легкие перечисления. Например, можно сказать, что направление 'north, 'south, 'east, или же 'west, Конечно, вы можете использовать строки для той же цели, но это будет немного менее эффективно. Использование чисел было бы плохой идеей; представлять информацию в максимально понятной и прозрачной форме.

В другом примере SXML - это представление XML с использованием списков, символов и строк. В частности, строки представляют символьные данные, а символы представляют имена элементов. Таким образом, XML <em>hello world</em> будет представлен значением (list 'em "hello world"), который можно записать более компактно '(em "hello world"),

Другое использование для символов в качестве ключей. Например, вы можете реализовать таблицу методов в виде словаря, отображающего символы в функции реализации. Чтобы вызвать метод, вы ищите символ, который соответствует имени метода. Lisp/Scheme/Racket делает это действительно простым, потому что язык уже имеет встроенное соответствие между идентификаторами (часть синтаксиса языка) и символами (значениями в языке). Это соответствие позволяет легко поддерживать макросы, которые реализуют пользовательские синтаксические расширения языка. Например, можно реализовать систему классов как макробиблиотеку, используя неявное соответствие между "именами методов" (синтаксическое понятие, определенное системой классов) и символами:

(send obj meth arg1 arg2)
=>
(apply (lookup-method obj 'meth) obj (list arg1 arg2))

(В других Лиспах то, что я сказал, в основном верно, но есть еще кое-что, о чем нужно знать, например, пакеты и функция против переменных слотов, IIRC.)

Символ - это объект с простым строковым представлением, которое (по умолчанию) гарантированно будет интернировано; т. е. любые два символа, которые написаны одинаково, являются одним и тем же объектом в памяти (ссылочное равенство).

Почему в Лиспе есть символы? Ну, это в значительной степени является артефактом того факта, что Лиспс встраивает свой собственный синтаксис в качестве типа данных языка. Компиляторы и интерпретаторы используют символы для представления идентификаторов в программе; Поскольку Lisp позволяет вам представлять синтаксис программы в виде данных, он предоставляет символы, потому что они являются частью представления.

Чем они полезны помимо этого? Ну и несколько вещей:

  • Лисп обычно используется для реализации встроенных доменных языков. Многие из методов, используемых для этого, происходят из мира компиляторов, поэтому символы являются здесь полезным инструментом.
  • Макросы в Common Lisp обычно включают в себя работу с символами более подробно, чем этот ответ. (Хотя, в частности, генерация уникальных идентификаторов для расширений макросов требует возможности генерировать символ, который гарантированно никогда не будет равен любому другому.)
  • Фиксированные типы перечисления лучше реализованы как символы, чем строки, потому что символы можно сравнивать по ссылочному равенству.
  • Существует много структур данных, которые вы можете построить, где вы можете получить выигрыш в производительности от использования символов и равенства ссылок.

Символы в lisp являются удобочитаемыми идентификаторами. Они все одинокие. Так что если вы объявите 'foo где-нибудь в своем коде, а затем снова используете' foo, это будет указывать на то же место в памяти.

Пример использования: разные символы могут представлять разные фигуры на шахматной доске.

Из структуры и интерпретации компьютерных программ, второе издание Гарольда Абельсона и Джеральда Джея Суссмана, 1996:

Чтобы манипулировать символами, нам нужен новый элемент в нашем языке: возможность заключать в кавычки объект данных. Предположим, мы хотим построить список (a b). Мы не можем сделать это с помощью (list a b), потому что это выражение создает список значений a и b, а не сами символы. Эта проблема хорошо известна в контексте естественных языков, где слова и предложения могут рассматриваться как семантические объекты или как символьные строки (синтаксические объекты). Обычная практика в естественных языках - использовать кавычки, чтобы указать, что слово или предложение следует трактовать буквально как строку символов. Например, первая буква "Джон" явно "J." Если мы скажем кому-то "произнесите ваше имя вслух", мы ожидаем услышать имя этого человека. Однако, если мы скажем кому-то "произнести" ваше имя "вслух", мы ожидаем услышать слова "ваше имя". Обратите внимание, что мы вынуждены вставлять кавычки, чтобы описать то, что может сказать кто-то другой. Мы можем следовать этой же практике, чтобы идентифицировать списки и символы, которые должны рассматриваться как объекты данных, а не как выражения для оценки. Однако наш формат цитирования отличается от формата естественных языков тем, что мы ставим кавычку (традиционно символ одинарной кавычки) только в начале цитируемого объекта. Мы можем избежать этого в синтаксисе Схемы, потому что мы используем пробелы и круглые скобки для разделения объектов. Таким образом, значение символа одинарной кавычки заключается в цитировании следующего объекта. Теперь мы можем различать символы и их значения:

(define a 1)

(define b 2)

(list a b)
(1 2)

(list ’a ’b)
(a b)

(list ’a b)
(a 2)

Списки, содержащие символы, могут выглядеть как выражения нашего языка:

(* (+ 23 45) (+ x 9)) 
(define (fact n) (if (= n 1) 1 (* n (fact (- n 1)))))

Пример: символическое дифференцирование

Символ - это просто специальное имя для значения. Значением может быть что угодно, но символ используется для ссылки на одно и то же значение каждый раз, и такого рода вещи используются для быстрых сравнений. Поскольку вы говорите, что вы - императивное мышление, они похожи на числовые константы в C, и именно так они обычно реализуются (внутренне хранимые числа).

Чтобы проиллюстрировать точку зрения Луиса Касильяса, может быть полезно наблюдать, чем символы отличаются от строк.

Пример ниже относится к mit-схеме (версия 10.1.10). Для удобства я использую эту функцию как eval:

      (define my-eval (lambda (x) (eval x (scheme-report-environment 5))))

Символ может легко вычисляться как значение или функция, которую он называет:

      (define s 2)      ;Value: s
(my-eval "s")     ;Value: "s"
(my-eval s)       ;Value: 2

(define a '+)     ;Value: a
(define b "+")    ;Value: b
(my-eval a)       ;Value: #[arity-dispatched-procedure 12]
(my-eval b)       ;Value: "+"

((my-eval a) 2 3) ;Value: 5
((my-eval b) 2 3) ;ERROR: The object "+" is not applicable.
Другие вопросы по тегам