2012-05-22 6 views
5

estoy en busca de una manera portátil, posiblemente, no detallado para inicializar una tabla hash en Common Lisp. P.ej. algo que funciona para tablas hash constantes, pero también para precargar hash variables. En CLISP estoy usando:Common Lisp: taquigrafía para inicializar una tabla hash con muchas entradas

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

pero desafortunadamente este formato sólo funciona en CLISP.

+0

https://github.com/vseloved/rutils/ blob/master/core/readtable.lisp # L10 –

+0

Tenga en cuenta que, por ejemplo, http://www.aiai.ed.ac.uk/~jeff/lisp/cl-pitfalls advierte contra el uso de tablas hash como valores para formularios 'defconstant'. – Hugh

+0

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é piensas sobre escribir una macro que envuelve make-hash-table y agrega la opción: initial-contents, la misma opción admitida en el estándar por, por ejemplo, make-array? Creo que esto probablemente no sea muy eficiente, ya que el contenido sería especificado por una alista que debe atravesarse, pero al menos es más consistente con la sintaxis de Lisp. –

Respuesta

6

se puede construir mediante programación una tabla hash en tiempo de 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. El compilador volcará la tabla hash al archivo FASL.

Esto entonces 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}> 

Creación de 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) 
+1

Muchas gracias Reiner! El único inconveniente es que es un poco detallado, pero se puede ayudar utilizando una macro. Soy un principiante de Lisp y no muy bueno en macros. De todos modos, aquí está la mía: '(defmacro ini-tabla hash (pares) ' (let ((almohadilla (maquillaje tabla hash: prueba de 'igual))) (circular para (valor de la clave) sobre, pares de #' cddr hacer (setf (hash de clave GetHash) de valor)) hash)) 'entonces yo:.' (defvar * ht * # (ini-hash-table '(a 1 B 2 C 3))) ' –

+1

@AntonioBonifati : cuando dudo, escriba una función, no una macro. No hay razón para que sea macro, ¿o sí? –

+1

Sí, gracias, lo sé, una buena razón para eso es que las macros son más difíciles de escribir y depurar. Pero si escribo una función en este caso, no puedo llamarlo 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 macro wrapper que permita configurar completamente make-hash-table mientras se agrega un parámetro de palabras clave de contenido inicial. Eso sería "agregar esta función al estándar" :) –