Hi everyone,
First off, I love Lisp. It's been about 7 weeks since I started learning
it (apart from a computer science Scheme module in my 1st year of
University). I've already completely rewritten a large program in it.
Anyway, I decided to avoid databases, and just store everything in text
files (which I do anyway). In Clisp, this is very easy to do:
(defun write-collection (filename hash-table)
"Write out a collection (stored in standard Lisp print form). Makes
loading of asm files much quicker, once processed and output with read-
collection"
(with-open-file (stream filename :direction :output)
(print hash-table stream )))
All the data inside the hashtable is stored in a format which can be read
back in easily:
(defun read-collection (filename)
"Read in a collection (stored in standard Lisp print form). Much
quicker for cached asm files than regexp'ing them. If the file does not
exist, it returns a blank hashtable for convenience (no don't, because we
don't know whether they want eq or equal hashtables"
(if (==(probe-file filename)NIL)
(return-from read-collection NIL))
; (return-from read-collection (make-hash-table)))
(let ((subroutine (make-hash-table)))
(let ((in (open filename)))
(if-progn in
(setf subroutine (read in))
(close in)))
subroutine))
The only problem is that this only appears to work in Clisp. Allegro,
Lispworks and Corman Lisp seem to output at this level of brevity:
#<EQL hash-table with 1 entry @ #x211ceac2>
Which is of course useful as a chocolate fireguard when I try to read it
back in!
Am I missing something here?
Jeremy Smith.
Jeremy Smith <············@decompiler.org> writes:
> Hi everyone,
>
> First off, I love Lisp. It's been about 7 weeks since I started learning
> it (apart from a computer science Scheme module in my 1st year of
> University). I've already completely rewritten a large program in it.
>
> Anyway, I decided to avoid databases, and just store everything in text
> files (which I do anyway). In Clisp, this is very easy to do:
> [...implementation dependant code...]
> The only problem is that this only appears to work in Clisp. Allegro,
> Lispworks and Corman Lisp seem to output at this level of brevity:
>
> #<EQL hash-table with 1 entry @ #x211ceac2>
>
> Which is of course useful as a chocolate fireguard when I try to read it
> back in!
But this is standard.
> Am I missing something here?
Yes. Writing hash tables readably is an implementation option.
Write your own format. For example, using #. and READ:
(defun print-hash-table (table &optional (stream *standard-output*))
(format stream "#.~S"
`(let ((table (make-hash-table
:test (function
,(case (hash-table-test table)
#+clisp (EXT:FASTHASH-EQ 'eq)
#+clisp (EXT:FASTHASH-EQL 'eql)
#+clisp (EXT:FASTHASH-EQUAL 'equal)
(otherwise (hash-table-test table))))
:size ,(hash-table-size table))))
(setf ,@(let ((assignments '()))
(maphash (lambda (k v)
(push `(quote ,v) assignments)
(push `(gethash ',k table) assignments))
table)
assignments))
table))
table)
(defun htable (kv &key (test (function eql)))
(loop
:with table = (make-hash-table :test test :size (truncate (length kv) 2))
:for (k v) on kv by (function cddr)
:do (setf (gethash k table) v)
:finally (return table)))
(with-output-to-string (*standard-output*)
(print-hash-table (htable (list :one 1 :two 2 :three 3)
:test (function eq)))
(print-hash-table (htable (list :one 1 :two 2 :three 3)))
(print-hash-table (htable (list "one" 1 "two" 2 "three" 3)
:test (function equal)))
(print-hash-table (htable (list '(1) 1 '(1 1) 2 '(1 1 1) 3)
:test (function equalp))))
--> "#.
(LET ((TABLE (MAKE-HASH-TABLE :TEST #'EQ :SIZE 3)))
(SETF (GETHASH ':ONE TABLE) '1 (GETHASH ':TWO TABLE) '2 (GETHASH ':THREE TABLE)
'3)
TABLE)#.
(LET ((TABLE (MAKE-HASH-TABLE :TEST #'EQL :SIZE 3)))
(SETF (GETHASH ':ONE TABLE) '1 (GETHASH ':TWO TABLE) '2 (GETHASH ':THREE TABLE)
'3)
TABLE)#.
(LET ((TABLE (MAKE-HASH-TABLE :TEST #'EQUAL :SIZE 3)))
(SETF (GETHASH '\"one\" TABLE) '1 (GETHASH '\"two\" TABLE) '2
(GETHASH '\"three\" TABLE) '3)
TABLE)#.
(LET ((TABLE (MAKE-HASH-TABLE :TEST #'EQUALP :SIZE 3)))
(SETF (GETHASH '(1) TABLE) '1 (GETHASH '(1 1) TABLE) '2
(GETHASH '(1 1 1) TABLE) '3)
TABLE)"
[145]>
(with-input-from-string
(*standard-input*
(with-output-to-string (*standard-output*)
(print-hash-table (htable (list :one 1 :two 2 :three 3)
:test (function eq)))
(print-hash-table (htable (list :one 1 :two 2 :three 3)))
(print-hash-table (htable (list "one" 1 "two" 2 "three" 3)
:test (function equal)))
(print-hash-table (htable (list '(1) 1 '(1 1) 2 '(1 1 1) 3)
:test (function equalp)))))
(print (read))(print (read))(print (read))(print (read))(values))
prints:
#S(HASH-TABLE :TEST EXT:FASTHASH-EQ (:THREE . 3) (:TWO . 2) (:ONE . 1))
#S(HASH-TABLE :TEST EXT:FASTHASH-EQL (:THREE . 3) (:TWO . 2) (:ONE . 1))
#S(HASH-TABLE :TEST EXT:FASTHASH-EQUAL ("three" . 3) ("two" . 2) ("one" . 1))
#S(HASH-TABLE :TEST EQUALP ((1 1 1) . 3) ((1 1) . 2) ((1) . 1))
--
__Pascal Bourguignon__ http://www.informatimago.com/
Nobody can fix the economy. Nobody can be trusted with their finger
on the button. Nobody's perfect. VOTE FOR NOBODY.
From: Kalle Olavi Niemitalo
Subject: Re: Reading and writing collections in non-CLisp interpreters
Date:
Message-ID: <87br27rvz8.fsf@Astalo.kon.iki.fi>
Jeremy Smith <············@decompiler.org> writes:
> (if-progn in
Is that the same as (when in ...)?
> #<EQL hash-table with 1 entry @ #x211ceac2>
If you bind *PRINT-READABLY* to T, then the printer will attempt
not to do this. If it doesn't know how, you'll get an error
instead, but during printing rather than reading, so your data
is hopefully still in memory.
Kalle Olavi Niemitalo <···@iki.fi> wrote in
···················@Astalo.kon.iki.fi:
> Jeremy Smith <············@decompiler.org> writes:
>
>> (if-progn in
>
> Is that the same as (when in ...)?
Oops, I didn't intend that macro to be in my sample code. It's just if
followed by a progn block (no else block), because I haven't come across
'when' yet. My error!
>> #<EQL hash-table with 1 entry @ #x211ceac2>
>
> If you bind *PRINT-READABLY* to T, then the printer will attempt
> not to do this. If it doesn't know how, you'll get an error
> instead, but during printing rather than reading, so your data
> is hopefully still in memory.
Yes, I just tried that in Allegro and got an error saying it couldn't
print it because it's a hashtable and the flag is set.
I'll follow Pascal's recommendation and read and write it with my own
functions, or convert it to an Alist and try reading and writing that.
I'll also take a look at cl-store.
Thanks everyone for the help,
Jeremy.
From: Alain Picard
Subject: Re: Reading and writing collections in non-CLisp interpreters
Date:
Message-ID: <87d5mni83f.fsf@memetrics.com>
Jeremy Smith <············@decompiler.org> writes:
> Hi everyone,
> Anyway, I decided to avoid databases, and just store everything in text
> files (which I do anyway). In Clisp, this is very easy to do:
I suggest you check out cl-store.