[gambit-list] questions about define-type, and structures in general

Marc Feeley feeley at iro.umontreal.ca
Mon May 23 17:12:49 EDT 2011


On 2011-05-22, at 4:10 PM, Matthew Koichi Grimes wrote:

> 
> 
> On Sun, May 22, 2011 at 6:39 AM, Mikael <mikael.rcv at gmail.com> wrote:
> 
> Why would you want this?
> 
>  As Adrien mentioned, it's a common practice in other languages, which I got used to (Python: override __repr__(), c++: override operator<<(), Java: override ToString(), etc). In my particular case, I was writing a doubly-linked list type, and wanted it to print (up to) its first three and last three values when displayed in the REPL.
>  
> Anyhow, you could make your own Gambit patch that adds a pp: procedure argument to define-type. Feel free to publish your patch on the Dumping grounds.
> 
> 
> I'll start by learning how to write macros! :D

Alternatively you can add a hook for your types in the "printer:

(define-type foo
  field1
  field2)

(set! ##wr
      (lambda (we obj)
        (cond ((foo? obj)
               (##wr-str we "#s(FOO ")
               (##wr we (foo-field1 obj))
               (##wr-str we " ")
               (##wr we (foo-field2 obj))
               (##wr-str we ")"))
              (else
               (##default-wr we obj)))))

(pp (make-foo 11 22)) ;; prints: #s(FOO 11 22)

> 
>  
> Similarly, how can I define a custom constructor that does something more complicated than assign arguments to slots? 
> 
> By defining your own procedure that does the job.
> 
> I figured it out. Here's an expanded answer for other beginners. It's actually as easy as:
> 
> (define-type my-type
>   ...
>   constructor: (lambda (<args>) <body>)
>   ...)

That's not correct.  The constructor: clause specifies the name of the constructor to override the default name, i.e.

(define-type foo
  constructor: make-bar
  field1
  field2)

(pp (make-bar 11 22))

You want something like this:

(define-type foo
  field1
  field2)

(define (construct-a-foo x)
  (make-foo x (* x x)))

> 
> 
> Someone else please verify that Gambit's define-record-type is just an alternative name for define-type, just like what call/cc is to call-with-current-continuation .
> 
> It seems that they aren't equivalent. Gambit's define-record-type comes from srfi-9, which uses positional arguments rather than define-type's keyword arguments:
> 
> http://srfi.schemers.org/srfi-9/srfi-9.html
> 
> From the example in the above link, we see that you can define a "pare" (pair) type as follows:
> (define-record-type :pare
> 
> 
>     (kons x y)
> 
>     pare?
>     (x kar set-kar!)
>     (y kdr))
> 
> We can then do a quick smoke-check to see that it worked:
> > (pare? (kons 1 2))
> #t
> 
> If we restart the interpreter and repeat the above two steps, this time using define-type instead of define-record type, we get:
> 
> > (define-type :pare (kons x y) pare? (x kar set-kar!) (y kdr))
> 
> 
> > (pare? (kons 1 2))
> 
> *** ERROR IN (console)@2.2 -- Unbound variable: pare?
> 
> That said, define-record-type does seem to be defined in terms of define-type, as can be seen in ~~/lib/nonstd.scm. Also, define-structure is equivalent to define-type:
> 
> 
> 
> 
> (define-runtime-macro (define-type . args)
>   (##define-type-expand 'define-type #f #f args))
> 
> (define-runtime-macro (define-structure . args)
>   (##define-type-expand 'define-structure #f #f args))
> 
> 
> 
> 
> (define-runtime-macro (define-record-type name constructor predicate . fields)
>   `(define-type ,name
>      constructor: ,constructor
>      predicate: ,predicate
>      , at fields))

Yes all three forms share a common implementation.  So wether you define a structure with a define-type or define-structure or define-record-type (with their respective syntaxes) the same implementation is obtained.

Marc




More information about the Gambit-list mailing list