Некоторые числа могут быть представлены только этими примитивами, просто довольно неудобно и сложно осмыслить, когда вы впервые видите это.
Подобно тому, как натуральные числа представляются с помощью множествувеличиваясь в размерах, они могут быть смоделированы в Лиспе как вложенные минусы.
Ноль будет пустым списком или ()
.Один из них будет синглтон-против, или (() . ())
.Два будет один плюс один или преемник единицы, где мы определяем преемника x как (cons () x)
, что, конечно, (() . (() . ()))
.Если вы принимаете Аксиому Бесконечности (и еще несколько, но в основном Аксиому Бесконечности для наших целей) и игнорируете ограничения памяти реальных компьютеров, это может точно представлять все натуральные числа.
Достаточно легко расширить это, чтобы представить все целые числа, а затем рациональные числа [1], но представить действительные числа в этой записи было бы (я думаю) невозможно.К счастью, это не умаляет нашего удовольствия, так как мы все равно не можем представить все реальное на наших компьютерах;мы обходимся поплавками и двойниками.Таким образом, наше представление столь же мощно.
В некотором смысле, 1
является просто синтаксическим сахаром для (() . ())
.
Ура теории множеств!Ура для Lisp!
EDIT Ах, для дальнейшего разъяснения, позвольте мне ответить на ваш вопрос о предикатах типа, хотя на данный момент это может быть понятно.Поскольку ваши числа имеют четкую форму, вы можете протестировать эти связанные списки с помощью функции собственного создания, которая проверяет эту конкретную структуру.Моя Схема не достаточно хороша, чтобы написать ее в Схеме, но я могу попытаться в Clojure.
Несмотря на это, вы, возможно, говорите, что это может дать вам ложные срабатывания: возможно, вы просто пытаетесь представить множества и в итоге вы получите ту же структуру, что и число в этой системе.На что я отвечаю: ну, в таком случае у вас есть на самом деле есть номер.
Итак, вы можете видеть, у нас есть довольно приличное представление чисел здесь, кроме того, сколько памяти они занимают (не наша забота) и как уродливо они выглядят при печати на REPL (также, ненаше беспокойство) и насколько неэффективно будет работать с ними (например, мы должны определить наше добавление и т. д. в терминах операций со списками: медленно и немного сложно.) Но ни один из них не вызывает беспокойства: скорость действительно должна и могла бызависит от деталей реализации, а не от того, что вы делаете этим языком.
Итак, здесь, в Clojure (но использование только тех вещей, к которым у нас есть доступ в основном в нашем простом Лиспе, равно numberp
. (Надеюсь,; не стесняйтесь поправлять меня, я неуклюжий как ад и т. д. оправдания и т. д.)
(defn numberp
[x]
(cond
(nil? x) true
(and (coll? x) (nil? (first x))) (numberp (second x))
:else false))
[1] Для целых чисел, представьте их как минусы натуральных клеток. Пусть первый элемент в минусыячейка будет "отрицательной" частью целого числа, а второй элемент будет "положительной" частью целого числа. Таким образом, -2 может быть представлен как (2, 0) или (4, 2) или (5,3) и т. Д.Если говорить рационально, пусть они представляются в виде целых ячеек целых чисел: например, (-2, 3) и т. д. Это дает нам возможность иметь одну и ту же структуру данных, представляющую одно и то же число: однако это можно исправить, написав функцииэтот тест проверяет два числа, чтобы определить, эквивалентны ли они: мы определяем эти функции в терминах уже существующих теорий множеств отношений эквивалентности, предлагаемых нам.Прикольные вещи:)