por que o gethash não retorna o valor da minha chave?

8

Programador experiente de lisp, esquema e clojure que está migrando para o elisp do python para automatizar tarefas básicas rotineiras, cotidianas e básicas: tive uma enorme surpresa do seguinte em ielm

ELISP> (setq h2 (make-hash-table))
#s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8 data ())
ELISP> (puthash "a" 1 h2)
1 (#o1, #x1, ?\C-a)
ELISP> (gethash "a" h2)
nil

Hã? A chave e o valor parecem estar presentes:

ELISP> h2
#s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8 data ("a" 1))

/ bate na testa. Eu devo estar perdendo algo totalmente óbvio. Info diz:

-- Function: gethash key table &optional default
 This function looks up KEY in TABLE, and returns its associated
 VALUE—or DEFAULT, if KEY has no association in TABLE.

ótimo. Vamos ver se podemos gethashretornar algo diferente de nil:

ELISP> (gethash "a" h2 'fubar) 
fubar

Uau. Ok, eu sou muito mais idiota do que eu pensava. O que diabos estou fazendo de errado?

Reb.Cabin
fonte

Respostas:

13

O teste de associação padrão para uma tabela de hash é eql. Se você quiser usar uma string como chave, defina-a equalcomo:

(setf hash (make-hash-table :test #'equal))
(puthash "a" 1 hash)
(gethash "a" hash)                      ; ==> 1

Para referência, aqui está a parte relevante da documentação:

make-hash-table é uma função embutida no `código fonte C '.

(make-hash-table &rest KEYWORD-ARGS)

Crie e retorne uma nova tabela de hash.

Os argumentos são especificados como pares de palavras-chave / argumentos. Os seguintes argumentos são definidos:

:testTESTE - TESTE deve ser um símbolo que especifique como comparar chaves. O padrão é eql. Predefinida são os testes eq, eqle equal. As funções de teste e hash fornecidas pelo usuário podem ser especificadas via define-hash-table-test.

Dan
fonte
Eu acho que tecnicamente você não está passando um símbolo como o :testparâmetro no seu exemplo ...
Sean
string-equalpode ter algumas vantagens equalse eu souber que minha tabela de hash possui cadeias apenas como chaves. Não sei ao certo por que o elisp possui ambos string-equale equal, porque equalpode ser usado em qualquer lugar que string-equalpossa ser usado modulo o fato de string-equalgerar erros de tipo quando você não fornece strings. Talvez esse seja um comportamento desejado.
Reb.Cabin