问题
I want to be able to do something like this:
(struct point (x y))
(define p1 (point 1 2))
(define p2 (point 10 20))
(+ p1 p2) ; -> (point 11 22)
Is it possible to teach a struct like point to work with built-in math operators like +?
The docs seem to manage to implement custom (equal? ...) handling in section 5.5 on this page. What I'm trying to do is quite similar ...
Or should I just define function like (point-add p1 p2)?
回答1:
You can either
- Go with
point-add Use your own
+that matches against all possible value types that you want to take on. This is sufficient if you know all possible value types beforehand, but it wouldn't be easy to extend it to include newly created struct definitions in client's code. For example:;; We will "shadow" Racket's + with our own +, but we still ;; need the functionality of Racket's +, so let's require ;; Racket's + but use the name racket:+ instead (require (only-in racket/base [+ racket:+])) (struct point (x y) #:transparent) (define (+ x y) (match* (x y) [((point a b) (point c d)) (point (+ a c) (+ b d))] [((point _ _) _) (error '+ "Can't add a point with non point")] [(_ (point _ _)) (error '+ "Can't add a point with non point")] [(_ _) (racket:+ x y)])) ;; in client's code (+ (point 1 2) (point 3 4)) ;=> (point 4 6) (+ 1 2) ;=> 3Define a new generics so that we can do something similar to
gen:equal+hashforequal?. For example:(require racket/generic (only-in racket/base [+ racket:+])) (define-generics addable (add addable _) #:fast-defaults ([number? (define (add x y) (racket:+ x y))])) (define + add) ;; in client's code (struct point (x y) #:transparent #:methods gen:addable [(define (add x y) (match* (x y) [((point a b) (point c d)) (point (+ a c) (+ b d))] [(_ _) (error 'add "Can't add a point with non point")]))]) (struct point-3d (x y z) #:transparent #:methods gen:addable [(define (add x y) (match* (x y) [((point-3d a b c) (point-3d d e f)) (point-3d (+ a d) (+ b e) (+ c f))] [(_ _) (error '+ "Can't add a point-3d with non point-3d")]))]) (+ (point 1 2) (point 3 4)) ;=> (point 4 6) (+ (point-3d 1 2 3) (point-3d 4 5 6)) ;=> (point-3d 5 7 9) (+ 1 2) ;=> 3To accept multiple arguments, modify (3) as follows
(define + (case-lambda [() 0] [(x . xs) (foldl add x xs)])) ;; client's code (+ (point 1 2) (point 3 4) (point 5 6)) ;=> (point 9 12) (+ 1 2 3) ;=> 6 (+) ;=> 0 (+ 1) ;=> 1 (+ (point-3d 1 2 3)) ;=> (point-3d 1 2 3)
来源:https://stackoverflow.com/questions/55876455/using-built-in-math-operators-with-custom-struct