work.
(define/contract (tuple-map-pairwise proc tuple1 tuple2)
(-> (-> real? real? real?) (or/c vector? point? color?) (or/c vector? point? color?) (or/c vector? point? color?))
(match (list tuple1 tuple2)
[(list (struct vector (i1 j1 k1)) (struct vector (i2 j2 k2)))
(vector (proc (vector-i tuple1) (vector-i tuple2))
(proc (vector-j tuple1) (vector-j tuple2))
(proc (vector-k tuple1) (vector-k tuple2)))]
[(list (struct point (x1 y1 z1)) (struct point (x2 y2 z2)))
(point (proc (point-x tuple1) (point-x tuple2))
(proc (point-y tuple1) (point-y tuple2))
(proc (point-z tuple1) (point-z tuple2)))]
[(list (struct color (r1 g1 b1)) (struct color (r2 g2 b2)))
(color (proc (color-r tuple1) (color-r tuple2))
(proc (color-g tuple1) (color-g tuple2))
(proc (color-b tuple1) (color-b tuple2)))]))
(define (tuple-op-by-constant op tuple c)
(tuple-map-elementwise (λ (e) (op e c)) tuple))
(define (tuple-op-pairwise op t1 t2 . tuples)
(cond [(empty? tuples) (tuple-map-pairwise op t1 t2)]
[else (apply tuple-op-pairwise op
(tuple-map-pairwise op t1 t2)
(car tuples)
(cdr tuples))]))
(define (vector+c v c)
(tuple-op-by-constant + v c))
(define (vector*c v c)
(tuple-op-by-constant * v c))
(define (vector+ u v . vectors)
(apply tuple-op-pairwise + u v vectors))
(define (vector- u v . vectors)
(apply tuple-op-pairwise - u v vectors))
Then I'll do something similar for points and colors. This library will probably be converted to Typed Racket, so the contracts are only temporary.
This seems to be the cleanest solution I think, and it's actually quite similar to the F# code I've written for the same project.
I know this seems simple, but wanted to check on people's thoughts on idiomatic ways in Racket, and to make sure I wasn't missing some secret sauce of structs or something else.