[racket] identifier used out of context error when making my own object-copy
For some reason I tried adding a (with-syntax ([%-stx %] [obj-stx obj]) …) and it actually helped.
I have no idea why you would need to do that though.
#lang racket/base (require (for-syntax racket/base))
(provide object-copy)
(require racket/class
(for-syntax
syntax/parse))
(module+ test
(require rackunit))
(define-syntax object-copy
(lambda (stx)
(syntax-parse stx
[(object-copy %-expr obj-expr
[field-id:id expr:expr]
...)
#:declare %-expr (expr/c #'class? #:name "class")
#:declare obj-expr (expr/c #'(is-a?/c %-expr) #:name "object")
(with-syntax ([ooo '...])
#'(let ([% %-expr.c] [obj obj-expr.c])
(define-values (name field-cnt all-field-syms field-accessor field-mutator super-class skipped?)
(class-info %))
(define remaining-field-syms (remove* '(field-id ...) all-field-syms))
(with-syntax ([%-stx %]
[obj-stx obj]
[(remaining-field-id ooo) remaining-field-syms])
(eval-syntax
#'(new %-stx
[field-id expr] ...
[remaining-field-id (get-field remaining-field-id obj-stx)] ooo
)))))]
)))
(module+ test
(define fish%
(class object% (init-field color weight)
(super-new) (inspect #f)))
(define marlin (new fish% [color 'orange-and-white] [weight 11]))
(define dory (object-copy fish% marlin
[color 'blue]))
(check-equal? dory (new fish% [color 'blue] [weight 11]))
(define shark%
(class fish% (init-field weeks-since-eating-fish)
(super-new) (inspect #f)))
(define bruce (new shark% [color 'grey] [weight 110] [weeks-since-eating-fish 3]))
(define chum (object-copy shark% bruce
[weight 90]
[weeks-since-eating-fish 0]))
(check-equal? chum (new shark% [color 'grey] [weight 90] [weeks-since-eating-fish 0]))
(define not-really-chum
(object-copy fish% bruce
[weight 90]))
(check-equal? not-really-chum (new fish% [color 'grey] [weight 90]))
)
On Apr 18, 2014, at 11:45 PM, Greg Hendershott <greghendershott at gmail.com> wrote:
> Although I have hardly any experience with racket/class, and I'm not
> very knowledgeable about how Racket structs are implemented, this got
> me curious to look at how struct-copy is implemented.
>
> First, your macro appears to be trying to work around the problem that
> `get-field-names` only makes sense at runtime (when given some
> particular object at runtime) -- but your macro is at compile-time.
> That's probably why you tried the nested `(with-syntax #'(
> (with-syntax (eval-syntax #'( )))))`.
>
>> And also, is there another version of field-names that takes a class instead
>> of an object, because I think that will create another problem when I get to
>> the last test (with not-really-chum).
>
> `class-info` looks promising for that. If only you could get a
> `class?` at compile time. But I haven't figured out how.
>
> Racket struct identifiers have a meaning both at run time (as a
> constructor) and at compile time (as a transformer binding to struct
> info):
>
> "5.7 Structure Type Transformer Binding
>
> The struct form binds the name of a structure type as a transformer
> binding that records the other identifiers bound to the structure
> type, the constructor procedure, the predicate procedure, and the
> field accessor and mutator procedures. This information can be used
> during the expansion of other expressions via syntax-local-value."
>
> As a result, struct-copy can use syntax-local-value to get the
> compile-time value, and pass it to extract-struct-info, to get a list
> of field identifiers.
>
> But unfortunately a class identifier does not seem to have any
> syntax-local-value at all (much less one that you could pass to
> class-info).
>
> That's my attempt at figuring it out. Hopefully one of the Racket
> experts can give you an actual solution (and/or correct any of what I
> wrote here).
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20140419/613b70be/attachment-0001.html>