Oleg Kiselyov 的pmatch 宏使得跨术语分布因子变得非常容易:
(define dist
(λ (expr)
(pmatch expr
[(* ,factor (+ . ,addends))
`(+ ,@(map (λ (addend)
(list factor addend))
addends))]
[else
expr])))
(dist '(* 5 (+ x y))) => (+ (5 x) (5 y))
主要技巧是匹配模式并从模式中相应插槽的表达式中提取元素。这需要一个带有棘手的表达式的cond
and到列表中的正确位置和正确的元素。写给你。let
cdr
car
pmatch
cond
let
因式分解出公用项更难,因为您必须查看所有子表达式以找到公因式,然后将它们拉出:
(define factor-out-common-factors
(λ (expr)
(pmatch expr
[(+ . ,terms) (guard (for-all (λ (t) (eq? '* (car t)))
terms))
(let ([commons (common-factors terms)])
`(* ,@commons (+ ,@(remove-all commons (map cdr terms)))))]
[else
expr])))
(define common-factors
(λ (exprs)
(let ([exprs (map cdr exprs)]) ; remove * at start of each expr
(fold-right (λ (factor acc)
(if (for-all (λ (e) (member factor e))
exprs)
(cons factor acc)
acc))
'()
(uniq (apply append exprs))))))
(define uniq
(λ (ls)
(fold-right (λ (x acc)
(if (member x acc)
acc
(cons x acc)))
'()
ls)))
(factor-out-common-factors '(+ (* 2 x) (* 2 y)))
=> (* 2 (+ (x) (y)))
输出可以再清理一些,这不包括分解出 1,并且 remove-all
丢失了,但我会把所有这些都留给你。