奥列格Kiselyov的pmatch macro使得跨术语分发因素很容易:
(define dist
(λ (expr)
(pmatch expr
[(* ,factor (+ . ,addends))
`(+ ,@(map (λ (addend)
(list factor addend))
addends))]
[else
expr])))
(dist '(* 5 (+ x y))) => (+ (5 x) (5 y))
主要的窍门是匹配模式和从该图案中的对应的狭槽提取的表达元件。这需要cond
和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
丢失了,但我将把所有这些留给你。
我没有采取过的第一个例子解析的时候,但你的第二个例子是“分解出”共同x或y。你是否想要那样做,或者“通过分发”?我知道两者都遵循分配法,但我想这些答案可能会有所不同,具体取决于你在找什么。 – NickO
准确地说,我只是想通过“分解”任何常见因素来表达一个表达式。这也许会是解释它的更好方式。 – user1641398