From: Jeremy Smith
Subject: Reading and writing collections in non-CLisp interpreters
Date: 
Message-ID: <Xns96E41E8B90B3jeremyalansmithsofth@80.5.182.99>
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.

From: Pascal Bourguignon
Subject: Re: Reading and writing collections in non-CLisp interpreters
Date: 
Message-ID: <877jcvsab2.fsf@thalassa.informatimago.com>
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.
From: Jeremy Smith
Subject: Re: Reading and writing collections in non-CLisp interpreters
Date: 
Message-ID: <Xns96E52E6BDBEA4jeremyalansmithsofth@62.253.170.163>
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.