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

我是Lisp新手,需要一些帮助。 我需要简化下一个表达式: 从
(+(+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)
      。这样做似乎很愚蠢:谁会写出这样一个表达式,但在简化复杂表达式时很容易出现这种情况

      该代码有一个详细的版本。可能还是有马车