I'd suggest just going with the structs and making them transparent. It's
only three structs and only with a handful of fields, abstracting over them
with map and fold doesn't seem worth the added complexity IMO. But if you'd
really like to map and fold over structs, I highly recommend using macros,
`syntax-parse` and the struct-id
<https://docs.racket-lang.org/syntax-classes/index.html?q=struct-id#%28form._%28%28lib._syntax%2Fparse%2Fclass%2Fstruct-id..rkt%29._struct-id%29%29>
syntax class to do so:
(require (for-syntax syntax/parse/class/struct-id)
syntax/parse/define)
(define-simple-macro (struct-map type:struct-id instance-expr:expr
map-function-expr:expr)
(let ([map-function map-function-expr]
[instance instance-expr])
(type.constructor-id (map-function (type.accessor-id instance)) ...)))
(struct point (x y z) #:transparent)
;; Outputs (point 2 3 4)
(struct-map point (point 1 2 3) add1)
On Sunday, January 31, 2021 at 4:20:03 PM UTC-8 making-a-racket wrote:
> Hello. I have a project where I am needing to represent vectors (in the
> mathematical sense), points, and colors. Both the vectors and points will
> be 3D. I'm having trouble knowing what's an idiomatic way to represent and
> interact with data types that are similar but different.
>
> In general, I could simply all represent them with a list or vector (in
> the Racket sense). So I could have:
>
> (define (vector i j k) #(i j k))
> (define (point x y z) #(x y z))
>
> Then I could readily use the existing vector functions, such as vector-map
> without having to define my own. But I don't super like this because I have
> to define my own accessor functions like vector-i and point-y and also
> don't get predicates like vector? for free.
>
> Another way is that I could use structs, but then I'm stuck implementing
> things myself and across the structs. To avoid the latter point, I could
> use pattern matching. So something like:
>
> (struct vector (i j k))
> (struct point (x y z))
>
> (define (tuple-map proc tuple)
> (match tuple
> [(struct vector (i j k)) (vector (proc (vector-i tuple))
> (proc (vector-j tuple))
> (proc (vector-k tuple)))]
> [(struct point (x y z)) (point (proc (point-x tuple))
> (proc (point-y tuple))
> (proc (point-z tuple)))]
> [(struct color (r g b)) (color (proc (color-r tuple))
> (proc (color-g tuple))
> (proc (color-b tuple)))]))
>
> But of course, this map doesn't take multiple tuples. And this feels
> awkward, because I'll need to implement other things, like fold. Map and
> fold would be used in defining new operators on vectors and points, like
> addition, normalization (for vectors only), etc.
>
> The ideal thing would be that I could define a struct for these types,
> that had the accessor functions like vector-i and predicates likes vector?
> but was actually represented by a vector (in the Racket sense) underneath
> the hood. Does something like this exist in Racket (not classes please).
>
> In F#, I did this same thing using F#'s records for the vector, point, and
> color data types, and they inherited an ITuple interface (F#'s immutable,
> functional data types can implement interfaces). Can Racket's stucts
> inherit from interfaces? Is there something I can do with generics?
>
> Thanks for any help on this design.
>
--
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 [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/racket-users/a0220f5d-e278-454a-bc57-b7686551e486n%40googlegroups.com.