I have a few questions about custom types in Gambit. I apologize if they seem elementary, but I couldn't find an answer in the docs or the mailing list archives, and I'm new to Scheme.
I've defined a new type "my-type" using define-type. How can I control how an instance of my-type gets displayed in the REPL? I know I can declare individual slots of my-type to be unprintable:, but I'd like to just be able to define a "print-my-type" function that gets called.
Similarly, how can I define a custom constructor that does something more complicated than assign arguments to slots?
Finally, there seem to be four options for defining structs in Gambit: define-structure, define-type, srfi-9's define-record-type, and meroon. Which should I be using? At the moment, I'm only defining very basic structures (e.g. doubly-linked lists), but my ambitions will probably grow.
Best, -- Matt
Afficher les réponses par date
2011/5/21 Matthew Koichi Grimes mkg@cs.nyu.edu
I have a few questions about custom types in Gambit. I apologize if they seem elementary, but I couldn't find an answer in the docs or the mailing list archives, and I'm new to Scheme.
I've defined a new type "my-type" using define-type. How can I control how an instance of my-type gets displayed in the REPL? I know I can declare individual slots of my-type to be unprintable:, but I'd like to just be able to define a "print-my-type" function that gets called.
Why would you want this? 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.
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.
Finally, there seem to be four options for defining structs in Gambit: define-structure, define-type, srfi-9's define-record-type, and meroon. Which should I be using? At the moment, I'm only defining very basic structures (e.g. doubly-linked lists), but my ambitions will probably grow.
Depends on your specific needs. I suppose define-type is more optimized than meroon.
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 .
Best, -- Matt
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
but I'd like to just be able to define a "print-my-type" function that gets called.
Why would you want this?
Mayby because he's used Common Lisp before, where it is something that is done quite often. Also, writing one's reader/writer for a home-made type is quite convenient…
P!
On Sun, May 22, 2011 at 6:39 AM, Mikael mikael.rcv@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
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>) ...)
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 ,@fields))
-- Matt
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
On 2011-05-22, at 4:10 PM, Matthew Koichi Grimes wrote:
On Sun, May 22, 2011 at 6:39 AM, Mikael mikael.rcv@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 ,@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