Преобразование Clojure типа не происходит

У меня есть следующая функция, которая дает мне хэш-карту:

(build-quarter-note-group 60)
;;=> {0.0 "c'", 2.0 "cisis'", -2.0 "ceses'", 0.5 "cih'", -0.5 "ceh'", 1.0 "cis'", -1.0 "ces'", 1.5 "cisih'", -1.5 "ceseh'"}

Тогда я получаю значения по getКлючи на карте в другой функции.

(defn keynum->name
  ([keynum] (->> 0.0 (get (build-quarter-note-group keynum))))
  ([keynum transposition] (->> (float transposition) (get (build-quarter-note-group keynum)))))

Поскольку ключи все плавают в keynum->name Функция, которую я попытался сделать приведение типа, но это произошло:

(keynum->name 60 1) ;;=> nil
(get (build-quarter-note-group 60) (float 1)) ;;=> nil

Что происходит с результатом (float 1)?

1 ответ

Решение

Цитирую ответ на вопрос, который я открыл в Clojure Jira:

Я считаю, что тот факт, что поиск поплавка на карте с максимум 8 ключами является случайностью реализации.

Причиной неудачи с большими картами и хэш-наборами является то, что значение хеша отличается для (double 1.0) и (float 1.0).

user=> (hash (float 1.0))
1065353216
user=> (hash 1.0)
1072693248

Все значения, такие как 1.0 и другие в вашем примере, по умолчанию набирают double. Обратите внимание, что если вы заставите ключи карты быть плавающими, то поиск будет успешным, даже если на карте более 8 ключей:

user=> (get {(float 1.0) "a" 2.0 "b" 3.0 "c" 4.0 "d" 5.0 "e" 6.0 "f" 7.0 "g" 8.0 "h" 1 "i"} (float 1)) 
"a"

Я предполагаю, что, за исключением случая, когда с маленькой картой происходит успешный поиск, все здесь работает так, как задумано.

Я полагаю, что причина того, что get с маленькой картой действительно находит соответствие для поиска (float 1), вероятно, в том, что реализация маленьких карт представляет собой ArrayMap, где ключи поиска последовательно сравниваются со всеми ключами в массиве с использованием clojure.core/= (или его эквивалент Java) и:

user=> (= (float 1) (double 1))
true

Итак, вкратце - ключи на вашей карте являются двойными, а не плавающими.

(get (build-quarter-note-group 60) (double 1)) => "cis'"

Другие вопросы по тегам