2012-05-22 10 views
5

Poszukuję prawdopodobnie niewerbalnego przenośnego sposobu inicjowania tabeli mieszania w Common Lisp. Na przykład. coś, co działa dla stałych tablic mieszających, ale także wstępnie wczytuje zmienne hasze. W CLISP używam:Common Lisp: skrót do zainicjowania tablicy mieszającej z wieloma wpisami

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

, ale niestety ten format działa tylko na CLISP.

+0

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

+0

Pamiętaj, że np. http://www.aiai.ed.ac.uk/~jeff/lisp/cl-pitfalls ostrzega przed używaniem tabel hash jako wartości dla "defconstant" formularzy. – Hugh

+0

Dziękuję wszystkim. Wydaje się, że tej podstawowej funkcji brakuje w standardzie i trzeba ją w jakiś sposób dodać. Zamiast wprowadzać nową składnię, naśladując Perla lub PHP, co sądzisz o pisaniu makra, które owija tablicę make-hash i dodaje opcję: treść początkowa, ta sama opcja obsługiwana w standardzie przez np. Make-tablicę? Myślę, że nie będzie to prawdopodobnie bardzo wydajne, ponieważ treść będzie określona przez alistę, która musi być przemierzana, ale jest co najmniej bardziej spójna ze składnią Lispa. –

Odpowiedz

6

Można programowo skonstruowania tabeli mieszania w czasie odczytu:

(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*) 

#. służy do oceny czasu odczytu. Następnie kompilator zrzuci tablicę haszującą do pliku FASL.

ten może być następnie zestawiane:

Korzystanie 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}> 

Tworzenie tabeli mieszania jako funkcję:

(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

Wielkie dzięki Reiner! Jedyną wadą jest to, że jest trochę gadatliwy, ale można to ułatwić za pomocą makra. Jestem początkującym Lispiem i niezbyt dobrym w makrach. W każdym razie tutaj jest mój: '(defmacro ini-hash-table (pairs) ' (let ((hash (make-hash-table: test 'equal))) (pętla for (wartość klucza) włączona, pary przez #' cddr do (setf (gethash key hash) value)) hash)) 'Następnie robię:' (defvar * ht * #. (ini-hash-table '(a 1 b 2 c 3))) ' –

+1

@AntonioBonifati : gdy wątpię napisać funkcję, a nie makro. Nie ma powodu, żeby to było makro, prawda? –

+1

Tak, dziękuję, wiem, dobrym tego powodem jest to, że makra są trudniejsze do napisania i debugowania. Ale jeśli w tym przypadku napiszę funkcję, nie mogę jej wywołać z #. Przynajmniej w ECL mówi mi, że jest niezdefiniowana. Myślę, że to efekt #. to znaczy, że dowolna zdefiniowana przez użytkownika funkcja nie jest dostępna w czasie odczytu. Zastanawiam się, czy można zapisać makro opakowanie, które pozwala w pełni skonfigurować makehash-table, dodając parametr: initial-contents keyword. To "doda tę funkcję do standardu" :) –