Схема продиктованных операций - PullRequest
1 голос
/ 13 апреля 2020

Я стремлюсь понять некоторый код hashmap в lisp и использую python в качестве ссылки.

Следующие два примерно одинаковы? И если так, как я могу увидеть, как выглядит мой объект dict?

# create dict
>>> my_dict = dict()                
> (define my_dict (make-hash-table))

# add keys
>>> my_dict['a'] = 1
>>> my_dict['b'] = 2
> (hash-set! my_dict 'a 1)
> (hash-set! my_dict 'b 2)

# get values
>>> my_dict.get('a')
> (hash-ref my_dict 'a)

# print the values?
print (my_dict)
> ??? How can I see what my hashmap contains in scheme?

1 Ответ

1 голос
/ 13 апреля 2020

Являются ли следующие два примерно одинаковыми?

Конечно, но я бы с осторожностью относился к изучению Scheme или любого Lisp, возвращаясь к Python .

Обратите внимание, что в схеме R6RS имеются таблицы процедур ha sh и ha sh как часть стандартных библиотек; это было не так со схемой R5RS. Следовательно, более ранние реализации Scheme обычно имели свои собственные реализации таблиц ha sh. Guile Scheme поддерживает R6RS ha sh таблицы и процедуры, но, похоже, поддерживает и более старые процедуры. Это также относится к Схеме, с которой я больше всего знаком, к Схеме Chez. В руководстве пользователя Chez Scheme говорится, что процедуры старого стиля включены в первую очередь ради совместимости со старыми реализациями Chez Scheme, но поддержка их может быть прекращена в будущем выпуске. Я не знаю, какова позиция Guile по этому вопросу, но я бы предложил, по возможности, использовать процедуры стандартной схемы для максимальной переносимости и для предотвращения таких будущих изменений в вашей реализации.

Guile до v3.0.2 в время написания этой статьи; OP версия v2.0.9, которой, насколько я могу судить, около 5 лет. Guile 2.0.14 поддерживает хеш-таблицы R6RS , поэтому я подозреваю, что Guile 2.0.9 также делает это. В любом случае я отвечу по стандартной схеме R6RS; адаптация к старой реализации Guile должна быть тривиальной, если необходимо.

Стандартная библиотека R6RS не имеет make-hash-table, но вместо этого имеет make-hashtable, make-eq-hashtable и make-eqv-hashtable , Процедура make-hashtable требует процедуры проверки эквивалентности ключей, тогда как make-eq-hashtable проверяет эквивалентность с eq? и make-eqv-hashtable проверяет eqv?.

Вместо hash-set!, Стандарт Библиотека имеет hashtable-set!, которая принимает те же аргументы, что и OP для hash-set!.

Вместо hash-ref, Стандартная библиотека имеет hashtable-ref. Это отличается от OP hash-ref тем, что для указания значения по умолчанию, когда ключ не найден, требуется третий аргумент.

По шагам OP можно создать и запросить таблицу ha sh. :

Chez Scheme Version 9.5
Copyright 1984-2017 Cisco Systems, Inc.

> (define my-dict (make-eq-hashtable))
> (hashtable-set! my-dict 'a 1)
> (hashtable-set! my-dict 'b 2)
> (hashtable-set! my-dict 'c 3)
> (hashtable-set! my-dict 'd 5)
> (hashtable-set! my-dict 'e 7)
> (hashtable-set! my-dict 'f 11)
> (hashtable-set! my-dict 'g 13)
> (hashtable-ref my-dict 'e #f)
7
> (hashtable-ref my-dict 'h #f)
#f
> my-dict
#<eq hashtable>

Как мне увидеть, что моя схема содержит в схеме?

Возможно, самое простое, что можно сделать, это создать список ассоциаций из таблицы ha sh. В R6RS нет стандартной процедуры, которая бы это делала, но был старый SRFI ( SRFI-69 ), который включал именно такую ​​процедуру: hash-table->alist , Возможно, что OP-реализация Guile включает в себя такую ​​процедуру, но ее легко реализовать с использованием стандартной схемы R6RS:

(define (hashtable->alist ht)
  (let-values (((ks vs) (hashtable-entries ht)))
    (vector->list (vector-map cons ks vs))))

Здесь процедура hashtable-entries принимает таблицу ha sh и возвращает два значения: вектор ключей и вектор соответствующих значений; let-values используется для связывания двух возвращаемых значений, чтобы их можно было использовать. vector-map возвращает вектор, образованный объединением элементов ks и vs с cons, а vector->list создает список из этого вектора.

> (hashtable->alist my-dict)
((f . 11) (e . 7) (c . 3) (b . 2) (a . 1) (g . 13) (d . 5))

Guile: Ради всего мира Полнота

Приведенное выше решение будет работать в Guile, но многие процедуры R6RS по умолчанию не распознаются в Guile. Чтобы вышеуказанное решение работало в Guile, сначала нужно что-то вроде:

(import (rnrs hashtables (6))         ; for R6RS hash tables
        (rnrs base (6)))              ; for R6RS let-values

После просмотра справочного руководства Guile 2.0.14 очевидно еще одно непортативное решение. Процедура hash-table->alist, описанная в руководстве, отсутствует, но в документации описано , как создать список ассоциаций из таблицы ha sh с помощью процедуры hash-map->list:

(hash-map->list cons my-dict)

Ожидается, что это сработает только для таблиц ha sh, созданных с помощью спецификаций реализации Guile c ha sh (например, make-hash-table), и может не работать с таблицами ha sh, созданными с помощью Конструкторы R6RS (например, make-eq-hashtable). Еще раз обратите внимание, что это решение должно работать в Guile (без импорта), но не переносимо.

...