Подтвердить что ты не робот

Почему использование ключевых слов или символов в качестве функций для поиска значений с карт работает?

Цитата из Радости Clojure, раздел 4.3.1 -

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

(def population {:zombies 2700, :humans 9})
(:zombies population)
;=> 2700
(println (/ (:zombies population)
(:humans population))
"zombies per capita")
; 300 zombies per capita

Мне не кажется, что здесь происходит. Как-то (:zombies population) нужно преобразовать в (get population :zombies), правильно? Как именно это работает? Ключевое слово оценивает себя, а не функцию. Читает ли читатель случаи, когда первое, что входит в список, является ключевым словом и добавляет get и перемещает ключевое слово в конец списка?

4b9b3361

Ответ 1

Ссылка официальная документация:

Ключевые слова реализуют IFn для invoke() одного аргумента (карты) с необязательным вторым аргументом (значение по умолчанию). Например (: mykey my-hash-map: none) означает то же самое, что (get my-hash-map: mykey: none). См. Get.

И Clojure может вызывать ключевое слово как функцию, потому что он реализует тот же интерфейс, что и функция. То же самое для символов...

Ответ 2

Ключевые слова являются функциями во всех отношениях. Магия читателя не задействована, поскольку вы увидите, если вы попробуете (let [m {:humans 100}, k :humans] (k m)). Надеюсь, вы согласитесь с тем, что читатель не может превратить это в get (возможно, компилятор, но вы можете притвориться, что значение t21 зависит от выражения if, которое компилятор не может предсказать, например, пользовательский ввод).

Поскольку типы данных типа Clojure являются интерфейсами, а объекты Java могут реализовывать множество интерфейсов, часть данных может иметь несколько типов. Это ключевое слово? Да. Это функция? Также да:

user> (keyword? :k)
true
user> (ifn? :k)
true
user> (.invoke :k {:k 1})
1