【问题标题】:Solving Infix Arithmatic in LISP在 LISP 中求解中缀算术
【发布时间】:2013-09-30 03:20:50
【问题描述】:
(defun solve (L)
    (cond
    ((null L) nil)
    (t(eval (list (car (cdr L)) (car L) (car (cdr (cdr L))))))))    

我的代码是一个简单的评估程序,只要输入类似于'(5 + 4) 就可以正常工作。但是我希望能够解决其他输入,例如 '(5 +( 3 - 1))'(6 + 5) - (4 / 2)。我的问题显然是如何处理括号。我尝试将 '( 的字面值与 ((equal (car L) '( ) (solve(cdr L))) 进行比较,但这只会抛出我的所有右括号不正常。有没有办法检查原子是否是括号?

【问题讨论】:

  • 这在我看来你需要递归。如果您不必使用cars 和cdrs 的显式链,这也会更容易。有这些组合,例如cadr,它有一个友好的备用名称second。我现在没有时间整理完整的答案,但也许这些提示会很好。 (如果是家庭作业,那就足够了,你应该完成剩下的工作。你的教授不会在没有期望你学会递归的情况下分配这个,所以如有必要,请查看它。如果不是家庭作业,请忽略这些最后的 cmets。 )
  • 我再添加一个提示。除非您尝试编写真正的解析器,否则不要显式地处理括号。让 Lisp 处理括号。只需处理给定括号内的内容。
  • @Mars +1 用于有关括号的 cmets。 Shrp91,火星的观点很有道理; '(5 + (3 - 1))的值是一个列表,其第一个元素是(数字)5,第二个元素是(符号)+,其第三个元素是一个列表,其第一、第二和第三个元素是@987654329 @、(符号)-1。根本不需要担心括号。但这提出了一个问题,当您说'(6 + 5) - (4 /2 ) 时,您实际上是在用什么称呼solve?这不是一个单一的表达式,间距很重要:(4 /2) 是一个包含元素 4 和(符号/2 的列表。
  • "... '(5 + (3 - 1)) 的值是一个列表,第一个元素是(数字)5,第二个元素是(符号)+,第三个元素是element 是一个列表,其第一个、第二个和第三个元素是 3、(符号)- 和 1。”这就是我所需要的。出于某种原因,我认为子列表的第一个元素将是括号。完全改变了我处理代码的方式,并在不久后得到它。

标签: lisp common-lisp infix-notation


【解决方案1】:

如果这是一个家庭作业问题,我希望你看看 Mars 的 cmets 而不是我的答案。如果您只使用我的代码,您将不会做得很好。另一方面,如果你真的通读了所有内容并真正理解了它,那就可以了。

就像 Mars 说的,我们需要递归。这很简单;如果我们有一个数字,返回它。

(defun solve (expression)
  (if (atom expression)
      expression
    'havent-dealt-with-this-yet))
[22]> (solve '3)
3

如果我们有一个列表,则取第二个,假设它是运算符,然后按照您在示例中的方式对其进行评估:

(defun solve (expression)
  (if (atom expression)
      expression
    (eval (list (second expression)
                (first expression)
                (third expression)))))
[25]> (solve 3)
3
[26]> (solve '(3 + 4))
7

酷。但是在这里,我们只是您的原始代码。如果我们有一个嵌套表达式会发生什么?

[27]> (solve '(3 + (2 * 2)))

*** - EVAL: 2 is not a function name; try using a symbol instead

好吧,这行不通。我们不能仅仅假设(first expression) or(第三个表达式)`中的任何一个都是值;它们本身可能是表达式。但是我们需要弄清楚表达式的值。假设我们有办法获取表达式并找到它的值。那么我们的代码可以是:

(defun solve (expression)
  (if (atom expression)
      expression
    (eval (list (second expression)
                (find-expression-value (first expression))
                (find-expression-value (third expression))))))

等等! solve 是一个接受表达式并找到其值的函数!

(defun solve (expression)
  (if (atom expression)
      expression
    (eval (list (second expression)
                (solve (first expression))
                (solve (third expression))))))
[43]> (solve 3)
3
[44]> (solve '(3 + 2))
5
[45]> (solve '((3 + 1) * (6 / 2)))
12

哒哒!

【讨论】:

  • 现在我们只需要添加带有运算符优先级和关联性规则的更长的表达式:-)
  • 你可以使用eval而不是funcall
  • 或者只是返回列表,将此代码从解释器更改为编译器到 Lisp :-)
  • 感谢 zck 展示了思维和工作方式,而不仅仅是答案。
  • 这基本上是我想出的。我的问题是认为子列表的第一个元素是括号。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-05
  • 1970-01-01
  • 2013-11-23
  • 1970-01-01
  • 1970-01-01
  • 2013-11-11
  • 1970-01-01
相关资源
最近更新 更多