Common Lisp: abreviatura para inicializar una tabla hash con muchas entradas

Estoy buscando una forma portátil posiblemente no detallada de inicializar una tabla hash en Common Lisp. Por ejemplo, algo que funcione para tablas hash constantes, pero también para precargar hash variables. En CLISP estoy usando:

(defconstant +my-map+ #S(HASH-TABLE :TEST FASTHASH-EQ
  (key1 . "value1")
  ...
  (keyN . "valueN")
))

pero desafortunadamente este formato solo funciona en CLISP.

preguntado el 22 de mayo de 12 a las 17:05

Tenga en cuenta que, por ejemplo, aiai.ed.ac.uk/~jeff/lisp/cl-pitfalls advierte contra el uso de tablas hash como valores para defconstant formas. -

Gracias a todos. Parece que esta característica fundamental falta en el estándar y debe agregarse de alguna manera. En lugar de introducir una nueva sintaxis, imitando a Perl o PHP, ¿qué piensa acerca de escribir una macro que envuelva make-hash-table y agregue la opción :initial-contents, la misma opción admitida en el estándar, por ejemplo, make-array? Creo que esto probablemente no será muy eficiente, ya que el contenido se especificaría mediante una lista que debe atravesarse, pero al menos es más consistente con la sintaxis de Lisp. -

4 Respuestas

Uno puede construir mediante programación una tabla hash en el momento de la lectura:

(defvar *ht* #.(let ((ht (make-hash-table)))
                 (loop for (key . value) in
                       '((a . 1) (b . 2) (c . 3))
                       do (setf (gethash key ht) value))
                 ht))

(describe *ht*)

#. se utiliza para la evaluación del tiempo de lectura. Luego, el compilador volcará la tabla hash en el archivo FASL.

Esto se puede compilar:

Usando SBCL:

* (compile-file "/tmp/test.lisp")

; compiling file "/private/tmp/test.lisp" (written 24 MAY 2012 10:08:49 PM):
; compiling (DEFVAR *HT* ...)
; compiling (DESCRIBE *HT*)

; /tmp/test.fasl written
; compilation finished in 0:00:00.360
#P"/private/tmp/test.fasl"
NIL
NIL
* (load *)

#<HASH-TABLE :TEST EQL :COUNT 3 {100299EA43}>
  [hash-table]

Occupancy: 0.2
Rehash-threshold: 1.0
Rehash-size: 1.5
Size: 16
Synchronized: no
T
* *ht*

#<HASH-TABLE :TEST EQL :COUNT 3 {100299EA43}>

Creando una tabla hash como una función:

(defun create-hashtable (alist
                         &key (test 'eql)
                         &aux (ht (make-hash-table :test test)))
  (loop for (key . value) in alist
        do (setf (gethash key ht) value))
  ht)

contestado el 25 de mayo de 12 a las 11:05

Muchas gracias Reiner! El único inconveniente es que es un poco detallado, pero eso se puede solucionar usando una macro. Soy un principiante de Lisp y no soy muy bueno con las macros. De todos modos, aquí está el mío: (defmacro ini-hash-table (pairs) (let ((hash (make-hash-table :test 'equal))) (loop for (key value) on ,pairs by #'cddr do (setf (gethash key hash) value)) hash))` Entonces lo hago : (defvar *ht* #.(ini-hash-table '(a 1 b 2 c 3))) - Antonio Bonifati 'Granjero'

@AntonioBonifati: cuando tenga dudas escriba una función, no una macro. No hay razón para que sea macro, ¿verdad? - Rainer Joswig

Sí, gracias, lo sé, una buena razón es que las macros son más difíciles de escribir y depurar. Pero si escribo una función en este caso, no puedo llamarla con #. Al menos en ECL me dice que no está definido. Creo que este es el efecto de #. es decir, cualquier función definida por el usuario no está disponible en tiempo de lectura. Me pregunto si se puede escribir un contenedor de macros que permita configurar completamente make-hash-table mientras se agrega un parámetro de palabra clave: contenido inicial. Eso "agregaría esta característica al estándar" :) - Antonio Bonifati 'Granjero'

@Antonio Bonifati. Si define la función en el mismo archivo, puede ponerla a disposición del compilador mediante una cláusula eval-when. - Rainer Joswig

Alejandría tiene la alist-hash-table función, que puede resultarle útil.

contestado el 23 de mayo de 12 a las 06:05

La Serapeum la biblioteca tiene dict:

(dict :a 1 :b 2 :c 3)
#<HASH-TABLE :TEST EQUAL :COUNT 3 {1008906D13}>

Puedes imprimir bastante tablas hash:

CL-USER> (toggle-pretty-print-hash-table)
T
CL-USER> (dict :a 1 :b 2 :c 3)
(dict
  :A 1
  :B 2
  :C 3
 ) 

que es una representación que se puede volver a leer.

También podemos usar pretty-print-hash-table directamente.

Serapeum es una biblioteca de alta calidad.

pd: mi CIELO meta-paquete hace dict disponible por defecto.

Respondido el 02 de Septiembre de 21 a las 10:09

Wow, una pregunta de hace 9 años obteniendo otra respuesta. Coincidentemente hacer hachís salió 2 meses después de que se hizo esta pregunta y generalmente es útil para este tipo de cosas.

Respondido el 03 de Septiembre de 21 a las 14:09

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.