[gambit-list] defining my own input/output ports

Marc Feeley feeley at iro.umontreal.ca
Mon Jun 22 09:29:36 EDT 2009


On 21-Jun-09, at 11:13 PM, lowly coder wrote:

> As I get more familiar with Gambit, I find it's notion of ports to  
> be really really useful. However, I don't know how to create these  
> structures myself. Can someone point me to some sample code? A  
> really great example would be something like:
>
> (define-type tagged-data tag data)
>
> then, as a piece of data is written to the output port, it's tagged  
> with a (increasing number), and when it's read off the input port,  
> it's a piece of tagged data
>
> so ssuppose I wrote
> 'a 'b 'c 'd 'e to the port
>
> then when I read from it, I get back
>
> (make-tagged-data 1 'a)
> (make-tagged-data 2 'b)
> ...
> (make-tagged-data 5 'e)
>
> The point of this isn't this particular problem, but to understand  
> what abstractions I need to provide when writing my own ports.

#|

The low-level port data structure is not made public because it has
a non-trivial interface which involves other non-trivial interfaces
(readtables, read environments, write environments, port locks, etc).

However, by using pipes it is possible to implement fancy encoders
and decoders for the data that is transferred on the port.  The basic
idea is to wrap the underlying port with a pipe, and create a thread
which transfers the data between the port and the pipe doing any
encoding/decoding that is needed.

Here's an example which adds a sequence number to each object
that is written with the "write" procedure.

|#

(define (open-output-file-seq path-or-settings)
   (receive (in out) (open-vector-pipe '(direction: input))
     (let* ((port
             (open-output-file path-or-settings))
            (pump
             (make-thread
              (lambda ()
                (let loop ((seqnum 0))
                  (let ((x (read in)))
                    (if (not (eof-object? x))
                        (let ((tagged (vector seqnum x)))
                          (write tagged port)
                          (newline port)
                          (force-output port)
                          (loop (+ seqnum 1)))
                        (close-port port))))))))
       (thread-start! pump)
       (##add-exit-job! ;; make sure pump is done when we exit
        (lambda ()
          (close-port out)
          (thread-join! pump)))
       out)))

(define p (open-output-file-seq "test-seq.txt"))

(write 'hello p)

(write 'world p)

(close-port p)

#|

The file test-seq.txt will contain:

#(0 hello)
#(1 world)

|#


Marc




More information about the Gambit-list mailing list