下面两个大致一样吗?
当然,但我会通过参考 Python 来学习 Scheme 或任何 Lisp。
注意R6RS Scheme has hash tables 和哈希表过程是标准库的一部分; R5RS 方案并非如此。因此,早期的 Scheme 实现通常有自己的哈希表实现。 Guile Scheme 确实支持 R6RS 哈希表和过程,但似乎也支持旧的过程。我最熟悉的Scheme Chez Scheme也是如此。 Chez Scheme 用户指南说,包含旧式过程主要是为了与旧 Chez Scheme 实现兼容,但在未来的版本中可能会放弃对它们的支持。我不知道 Guile 对此的立场是什么,但我建议尽可能使用标准方案程序以实现最大的可移植性并防止未来在您的实施中发生此类变化。
在撰写本文时,Guile 已达到 v3.0.2; OP版本是v2.0.9,据我所知,目前大约有5年的历史。 Guile 2.0.14 supports R6RS hashtables,所以我怀疑 Guile 2.0.9 也是如此。无论如何,我将使用 R6RS 标准方案来回答;如有必要,调整到旧的 Guile 实现应该是微不足道的。
R6RS Standard Library 没有make-hash-table,而是有make-hashtable、make-eq-hashtable 和make-eqv-hashtable。 make-hashtable 过程需要一个测试密钥等效性的过程,而make-eq-hashtable 与eq? 测试等效性,make-eqv-hashtable 与eqv? 测试。
标准库有hashtable-set!,而不是hash-set!,它采用与OP 对hash-set! 相同的参数。
标准库有hashtable-ref,而不是hash-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>
如何查看我的 hashmap 在方案中包含的内容?
可能最简单的做法是从哈希表创建一个关联列表。 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:为了完整性
上述解决方案在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 过程,但是the documentation describes 如何使用hash-map->list 过程从哈希表创建关联列表:
(hash-map->list cons my-dict)
这只能用于使用 Guile 的特定于实现的哈希表构造函数(例如make-hash-table)创建的哈希表,并且可能不适用于使用 R6RS 构造函数(例如make-eq-hashtable)创建的哈希表。再次注意,这个解决方案应该在 Guile 中工作(没有任何导入),但不可移植。