Re: [racket-users] Struct initialization?

2018-03-13 Thread Philip McGrath
I've written an experimental macro `structure` that tries to make it
convenient to write custom wrappers for the constructor and the match
expander that use the name of the struct:
http://docs.racket-lang.org/adjutor/Experimental.html#%28form._%28%28lib._adjutor%2Fmain..rkt%29._structure%29%29
If you're interested in doing something like that as a one-off, the
implementation is here
.
Basically the approach is to use #:name and #:constructor-name to avoid
binding the name of the struct (which is still used for printing and error
reporting), define the actual constructor wrapper function you want, then
to define-syntax the name of the struct to a compile-time data structure
implementing prop:procedure, prop:struct-info, and prop:match-expander
(unless you want the default match behavior). That sounds a little more
complicated than it is: here's an example that doesn't override the default
match behavior.

#lang racket

(require (for-syntax racket/struct-info
 syntax/transformer
 ))

(begin-for-syntax
  (struct info-record (info macro)
#:property prop:procedure (struct-field-index macro)
#:property prop:struct-info (λ (this) (info-record-info this

(struct foo (A B C)
  #:transparent
  #:name foo-transformer
  #:constructor-name raw-make-foo)

(define (make-foo A B)
  (raw-make-foo A B (+ A B)))

(define-syntax foo
  (info-record
   (extract-struct-info (syntax-local-value #'foo-transformer))
   (make-variable-like-transformer #'make-foo)))

All of that said, in practice, I haven't found myself reaching for my
`structure` macro as frequently as I expected to when I wrote it. Most of
the cases seem to fall into one of two categories. If I'm writing a trivial
script, I usually find it sufficient to follow the convention of writing a
constructor wrapper named `make-foo`. On the other hand, in a larger
project, it becomes reasonable to use the module system to manage renaming
and encapsulation, and typically I have a bunch of data-structures that I
want to handle in a consistent, project-specific way.


-Philip

On Sat, Mar 10, 2018 at 1:19 AM, Milo Turner  wrote:

> You can also set! the extra constructor
>
> #lang racket
>
> (struct foo [a b c]
>   #:extra-constructor-name -foo
>   #:transparent)
>
> (define ((foo* make-foo) a b)
>   (make-foo a b (+ a b)))
>
> (set! -foo (foo* -foo))
>
> (foo 1 2) ; -> (foo 1 2 3)
> (match (foo 1 2)
>   [(foo _ _ c) c]) ; -> 3
>
> However I usually just provide a custom make-X function as the only
> constructor. If you're hiding initialization details through the
> constructor it seems a bit
> odd to not hide these details in the match expander. So if you really want
> full encapsulation you should write the match expander as well. But in
> practice
> that's usually overkill.
>
> On Friday, March 9, 2018 at 10:24:00 PM UTC-5, Jon Zeppieri wrote:
>
>>
>>
>> On Fri, Mar 9, 2018 at 9:35 PM, Kevin Forchione  wrote:
>>
>>> Is it possible to initialize a struct field based on values from
>>> previously defined fields? Something equivalent to let* where
>>>
>>> >(struct foo (A B C))
>>> >(foo 1 2) would produce (foo 1 2 3) for example?
>>>
>>>
>>> As far as I know, the only way to do this is to write your own function
>> that calls the struct constructor. You can do this in a module, and only
>> export your constructor, instead of the default struct constructor.
>>
>> If you want the constructor and the match expander to use the same
>> identifier, then you need to do a bit more work.  For example:
>>
>> ```
>> #lang racket/base
>>
>> (require racket/match
>>  (for-syntax racket/base
>>  syntax/transformer))
>>
>> (struct foo* (A B C))
>>
>> (define (foo a b)
>>   (foo* a b (+ a b)))
>>
>> (define-match-expander $foo
>>   (syntax-rules ()
>> [(foo a b c) (foo* a b c)])
>>   (make-variable-like-transformer #'foo))
>>
>> (provide (rename-out [$foo foo]
>>  [foo*-A foo-A]
>>  [foo*-B foo-B]
>>  [foo*-C foo-C])))
>> ```
>>
>> Of course, even here, an instance will print as #. You can
>> implement gen:custom-write to fix that.
>>
>> There might be a better way to do this, but this is what I've used in the
>> past.
>>
>> - Jon
>>
>>
>>
>>
>> --
> You received this message because you are subscribed to the Google Groups
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to racket-users+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Struct initialization?

2018-03-09 Thread Milo Turner
You can also set! the extra constructor

#lang racket

(struct foo [a b c]
  #:extra-constructor-name -foo
  #:transparent)

(define ((foo* make-foo) a b)
  (make-foo a b (+ a b)))

(set! -foo (foo* -foo))

(foo 1 2) ; -> (foo 1 2 3)
(match (foo 1 2)
  [(foo _ _ c) c]) ; -> 3

However I usually just provide a custom make-X function as the only 
constructor. If you're hiding initialization details through the 
constructor it seems a bit 
odd to not hide these details in the match expander. So if you really want 
full encapsulation you should write the match expander as well. But in 
practice
that's usually overkill.

On Friday, March 9, 2018 at 10:24:00 PM UTC-5, Jon Zeppieri wrote:
>
>
>
> On Fri, Mar 9, 2018 at 9:35 PM, Kevin Forchione  > wrote:
>
>> Is it possible to initialize a struct field based on values from 
>> previously defined fields? Something equivalent to let* where
>>
>> >(struct foo (A B C))
>> >(foo 1 2) would produce (foo 1 2 3) for example?
>>
>>
>> As far as I know, the only way to do this is to write your own function 
> that calls the struct constructor. You can do this in a module, and only 
> export your constructor, instead of the default struct constructor.
>
> If you want the constructor and the match expander to use the same 
> identifier, then you need to do a bit more work.  For example:
>
> ```
> #lang racket/base
>
> (require racket/match
>  (for-syntax racket/base
>  syntax/transformer))
>
> (struct foo* (A B C))
>
> (define (foo a b)
>   (foo* a b (+ a b)))
>
> (define-match-expander $foo
>   (syntax-rules ()
> [(foo a b c) (foo* a b c)])
>   (make-variable-like-transformer #'foo))
>
> (provide (rename-out [$foo foo]
>  [foo*-A foo-A]
>  [foo*-B foo-B]
>  [foo*-C foo-C])))
> ```
>
> Of course, even here, an instance will print as #. You can implement 
> gen:custom-write to fix that.
>
> There might be a better way to do this, but this is what I've used in the 
> past.
>
> - Jon
>
>
>
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Struct initialization?

2018-03-09 Thread Jon Zeppieri
On Fri, Mar 9, 2018 at 9:35 PM, Kevin Forchione  wrote:

> Is it possible to initialize a struct field based on values from
> previously defined fields? Something equivalent to let* where
>
> >(struct foo (A B C))
> >(foo 1 2) would produce (foo 1 2 3) for example?
>
>
> As far as I know, the only way to do this is to write your own function
that calls the struct constructor. You can do this in a module, and only
export your constructor, instead of the default struct constructor.

If you want the constructor and the match expander to use the same
identifier, then you need to do a bit more work.  For example:

```
#lang racket/base

(require racket/match
 (for-syntax racket/base
 syntax/transformer))

(struct foo* (A B C))

(define (foo a b)
  (foo* a b (+ a b)))

(define-match-expander $foo
  (syntax-rules ()
[(foo a b c) (foo* a b c)])
  (make-variable-like-transformer #'foo))

(provide (rename-out [$foo foo]
 [foo*-A foo-A]
 [foo*-B foo-B]
 [foo*-C foo-C])))
```

Of course, even here, an instance will print as #. You can implement
gen:custom-write to fix that.

There might be a better way to do this, but this is what I've used in the
past.

- Jon

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[racket-users] Struct initialization?

2018-03-09 Thread Kevin Forchione
Is it possible to initialize a struct field based on values from previously 
defined fields? Something equivalent to let* where 

>(struct foo (A B C))
>(foo 1 2) would produce (foo 1 2 3) for example?

Thanks!
Kevin

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.