Схема дикт операций

Я хочу понять некоторый код хэш-карты в 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?

person samuelbrody1249    schedule 12.04.2020    source источник
comment
Что это за код в посте? Я уверен, что имелось в виду my_dict вместо m. Какая схема используется? В схеме R6RS нет ни hash-set!, ни hash-ref; у него есть hashtable-set! и hashtable-ref, а hashtable-ref требует 3-го аргумента, указывающего возвращаемое значение по умолчанию.   -  person ad absurdum    schedule 13.04.2020
comment
@exnihilo обновлен с опечаткой. Как узнать, какую версию схемы я использую?   -  person samuelbrody1249    schedule 13.04.2020
comment
схема@(хитрый-пользователь) [13]› (версия) $25 = 2.0.9   -  person samuelbrody1249    schedule 13.04.2020


Ответы (1)


Следующие два примерно одинаковы?

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

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

На момент написания этой статьи Guile имеет версию до версии 3.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, можно создать и запросить хеш-таблицу:

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>

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

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

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

Здесь процедура hashtable-entries берет хеш-таблицу и возвращает два значения: вектор ключей и вектор соответствующих значений; 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, но многие процедуры 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 процедура, но документация описывает, как создать список ассоциаций из хеш-таблицы с помощью процедуры hash-map->list:

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

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

person ad absurdum    schedule 13.04.2020