如何在Racket模式匹配中避免重复代码并保留变量绑定
方案1:批量匹配自动生成列表(推荐满足你要的(a,c)/(b,d)绑定需求)
你示例中最后用到的struct->list加...的模式已经是最优方案之一,无需重复写app逻辑,所有需要应用相同规则的字段会自动把匹配到的变量聚合为列表:
(require racket/struct) (struct my-struct (field1 field2 field3) #:transparent) (define s (my-struct '(3 4) '(6 5) '(7 8))) (match s [(? my-struct? (app struct->list (list `(,x ,y) (app (curryr sort <) `(,lo ,hi)) ...))) ; 此时 lo 自动绑定为 '(5 7) 也就是你要的 `(,a ,c) ; hi 自动绑定为 '(6 8) 也就是你要的 `(,b ,d) (apply - `(,@(map (curry apply *) (map cons (list x y) `(,lo ,hi))) ,(expt (car lo) (cadr hi))))])
这种方案的优势是后续如果给结构体新增需要应用相同排序规则的字段,完全不需要修改匹配逻辑,自动适配新字段。
方案2:自定义匹配扩展保留单变量绑定
如果你需要保留a/b/c/d四个变量的单独绑定,不想聚合为列表,可以用define-match-expander把重复的app逻辑封装为可复用的匹配模式:
; 定义可复用的排序对匹配模式 (define-match-expander sorted-pair (syntax-rules () [(_ lo-var hi-var) (app (curryr sort <) `(,lo-var ,hi-var))])) ; 匹配时直接调用自定义模式,完全无重复代码 (match s [(my-struct `(,x ,y) (sorted-pair a b) (sorted-pair c d)) ; 这里可以直接用a/b/c/d四个单独变量 (- (* x a c) (* y b d) (expt a d))])
这种方案适合只需要给少量字段应用相同规则、需要单独操作每个变量的场景,代码可读性更高。
内容的提问来源于stack exchange,提问作者ByteEater
相关产品推荐
相关产品推荐

