【问题标题】:Scheme dict operations方案字典操作
【发布时间】:2020-04-12 21:18:18
【问题描述】:

我希望了解一些 lisp 中的 hashmap 代码,并使用 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?

【问题讨论】:

  • 帖子中的这段代码是什么?我确信my_dict 的意思是而不是m。正在使用什么方案? R6RS 方案没有hash-set!hash-ref;它有hashtable-set!hashtable-ref,而hashtable-ref 需要第三个参数来指定默认返回值。
  • @exnihilo 更新了错字。如何找出我正在使用的方案版本?
  • scheme@(guile-user) [13]> (版本) $25 = "2.0.9"

标签: scheme lisp guile


【解决方案1】:

下面两个大致一样吗?

当然,但我会通过参考 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-hashtablemake-eq-hashtablemake-eqv-hashtablemake-hashtable 过程需要一个测试密钥等效性的过程,而make-eq-hashtableeq? 测试等效性,make-eqv-hashtableeqv? 测试。

标准库有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-&gt;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 返回一个由ksvs 的元素与cons 组合而成的向量,vector-&gt;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-&gt;alist 过程,但是the documentation describes 如何使用hash-map-&gt;list 过程从哈希表创建关联列表:

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

这只能用于使用 Guile 的特定于实现的哈希表构造函数(例如make-hash-table)创建的哈希表,并且可能不适用于使用 R6RS 构造函数(例如make-eq-hashtable)创建的哈希表。再次注意,这个解决方案应该在 Guile 中工作(没有任何导入),但不可移植。

【讨论】:

    猜你喜欢
    • 2012-03-20
    • 1970-01-01
    • 1970-01-01
    • 2018-08-11
    • 2019-01-29
    • 1970-01-01
    • 1970-01-01
    • 2018-05-10
    相关资源
    最近更新 更多