¿por qué gethash no devuelve el valor de mi clave?

8

Experimentado programador de lisp, esquema y clojure haciendo el cambio a elisp desde python para automatizar tareas básicas, cotidianas y básicas: me sorprendió enormemente lo siguiente en 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

eh? La clave y el valor parecen estar presentes:

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

/ bofetadas en la frente. Debo estar perdiendo algo totalmente obvio. La información dice:

-- 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.

estupendo. Veamos si podemos gethashdevolver algo más que nil:

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

Guau. Ok, soy mucho más tonto de lo que pensaba. ¿Qué demonios estoy haciendo mal?

Cabaña Reb.
fuente

Respuestas:

13

La prueba de pertenencia predeterminada para una tabla hash es eql. Si desea utilizar una cadena como clave, configúrela en su equallugar:

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

Como referencia, aquí está la parte relevante de la cadena de documentación:

make-hash-table es una función incorporada en el 'código fuente C'.

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

Crear y devolver una nueva tabla hash.

Los argumentos se especifican como pares de palabras clave / argumento. Se definen los siguientes argumentos:

:testTEST - TEST debe ser un símbolo que especifique cómo comparar claves. Por defecto es eql. Predefinidos son las pruebas eq, eqly equal. Las funciones de prueba y hash proporcionadas por el usuario se pueden especificar mediante define-hash-table-test.

Dan
fuente
Supongo que técnicamente no estás pasando un símbolo como :testparámetro en tu ejemplo ...
Sean
string-equalpodría tener algunas ventajas sobre equalsi sé que mi tabla hash tiene cadenas solo como claves. No estoy seguro de por qué elisp tiene ambos string-equaly equal, ya que equalse puede usar en cualquier lugar que string-equalse pueda usar módulo, el hecho de que string-equalarroja errores de tipo cuando no le da cadenas. Tal vez ese es un comportamiento deseado.
Reb.Cabin