Lisp 简化符号表达式
我是Lisp新手,需要一些帮助。 我需要简化下一个表达式: 从Lisp 简化符号表达式,lisp,common-lisp,Lisp,Common Lisp,我是Lisp新手,需要一些帮助。 我需要简化下一个表达式: 从(+(+ab)C)到(+ab C) 从(-ab)C)到(-ab C) 如果你能帮我解决其中一个问题,我会明白我需要如何解决下一个问题 非常感谢。假设您有一个与此模式匹配的输入,(+e1…en),您希望递归地将所有e1简化为en,这将为您提供s1,…,sn,然后提取以+开头的所有si,将其参数上移一级,到您正在构建的简化表达式 表达式e与上述模式匹配,如果(and(consp e)(eq'+(care)) 然后,所有的ei仅由(cdr
(+(+ab)C)
到(+ab C)
从(-ab)C)
到(-ab C)
如果你能帮我解决其中一个问题,我会明白我需要如何解决下一个问题
非常感谢。假设您有一个与此模式匹配的输入,
(+e1…en)
,您希望递归地将所有e1
简化为en
,这将为您提供s1
,…,sn
,然后提取以+
开头的所有si
,将其参数上移一级,到您正在构建的简化表达式
- 表达式
与上述模式匹配,如果e
(and(consp e)(eq'+(care))
- 然后,所有的
仅由ei
列表给出(cdre)
- 以
为例,如何简化它(+)
- 要将函数
应用于值列表,请调用f
(mapcar#f list)
- 要根据谓词
将列表拆分为两个列表,可以使用循环:p
有一种纯粹的功能性方法来写这个,你能理解吗(let ((sat nil) (unsat nil)) (dolist (x list (values sat unsat)) (if (funcall predicate x) (push x sat) (push x unsat))))
- 这是一个用Racket编写的简单化程序,它实现了一个相当简单的简化程序,用于
+
。请注意,这并不是什么严肃的问题:这只是我在思考这个问题时输入的内容
这使用了Racket的模式匹配,可能是以一种幼稚的方式,来完成一些工作
(define/match (simplify expression)
;; simplifier driver
(((cons op args))
;; An operator with some arguments
;; Note that this assumes that the arguments to operators are always
;; expressions to simplify, so the recursive level can be here
(simplify-op op (map simplify args)))
((expr)
;; anything else
expr))
(define op-table (make-hash))
(define-syntax-rule (define-op-simplifier (op args) form ...)
;; Define a simplifier for op with arguments args
(hash-set! op-table 'op (λ (args) form ...)))
(define (simplify-op op args)
;; Note the slightly arcane fallback: you need to wrap it in a thunk
;; so hash-ref does not try to call it.
((hash-ref op-table op (thunk (λ (args) (cons op args)))) args))
(define-op-simplifier (+ exprs)
;; Simplify (+ ...) by flattening + in its arguments
(let loop ([ftail exprs]
[results '()])
(if (null? ftail)
`(+ ,@(reverse results))
(loop (rest ftail)
(match (first ftail)
[(cons '+ addends)
(append (reverse addends) results)]
[expr (cons expr results)])))))
有可能比这更具侵略性。例如,我们可以合并文本数字的运行,因此我们可以将(+123A4)
简化为
(+6 a 4)
(注意,除非所有的算术都是精确的,否则将其进一步简化为(+10 a)
)通常是不安全的)。下面是一个函数,它对+
和*
进行合并:
(define (coalesce-literal-numbers f elts)
;; coalesce runs of literal numbers for an operator f.
;; This relies on the fact that (f) returns a good identity for f
;; (so in particular it returns an exact number). Thisis true for Racket
;; and CL and I think any Lisp worth its salt.
;;
;; Note that it's important here that (eqv? 1 1.0) is false.
;;;
(define id (f))
(let loop ([tail elts]
[accum id]
[results '()])
(cond [(null? tail)
(if (not (eqv? accum id))
(reverse (cons accum results))
(reverse results))]
[(number? (first tail))
(loop (rest tail)
(f accum (first tail))
results)]
[(eqv? accum id)
(loop (rest tail)
accum
(cons (first tail) results))]
[else
(loop (rest tail)
id
(list* (first tail) accum results))])))
这是一个改进的简化程序,用于+
,它使用了这个。它注意到,(+x)
可以简化为x
(define-op-simplifier (+ exprs)
;; Simplify (+ ...) by flattening + in its arguments
(let loop ([ftail exprs]
[results '()])
(if (null? ftail)
(let ([coalesced (coalesce-literal-numbers + (reverse results))])
(match coalesced
[(list something)
something]
[exprs
`(+ ,@exprs)]))
(loop (rest ftail)
(match (first ftail)
[(cons '+ addends)
(append (reverse addends) results)]
[expr (cons expr results)])))))
下面是使用此增强简化器的示例:
> (simplify 'a)
'a
> (simplify 1)
1
> (simplify '(+ 1 a))
'(+ 1 a)
> (simplify '(+ a (+ b c)))
'(+ a b c)
> (simplify '(+ 1 (+ 3 c) 4))
'(+ 4 c 4)
> (simplify '(+ 1 2 3))
6
要获得更多的价值,您可以注意到,*
的简化器实际上是相同的,并将其更改为:
(define (simplify-arith-op op fn exprs)
(let loop ([ftail exprs]
[results '()])
(if (null? ftail)
(let ([coalesced (coalesce-literal-numbers fn (reverse results))])
(match coalesced
[(list something)
something]
['()
(fn)]
[exprs
`(,op ,@exprs)]))
(loop (rest ftail)
(match (first ftail)
[(cons the-op addends)
#:when (eqv? the-op op)
(append (reverse addends) results)]
[expr (cons expr results)])))))
(define-op-simplifier (+ exprs)
(simplify-arith-op '+ + exprs))
(define-op-simplifier (* exprs)
(simplify-arith-op '* * exprs))
现在呢
(simplify '(+ a (* 1 2 (+ 4 5)) (* 3 4) 6 (* b)))
'(+ a 36 b)
这是相当整洁的
您可以更进一步,例如,当合并运算符的数字时,您可以简单地删除该运算符的标识序列:(*1A1B)
可以简化为(*AB)
,而不是(*1A1B)
。这样做似乎很愚蠢:谁会写出这样一个表达式,但在简化复杂表达式时很容易出现这种情况
该代码有一个详细的版本。可能还是有马车