定义用于在Lisp中评估中缀表达式的函数

时间:2014-08-21 19:35:04

标签: lisp common-lisp infix-notation

我在Lisp中不是很好,我需要做一个允许评估中缀表达式的函数。例如:(+ 2 3) -> (infixFunc 2 + 3)。我尝试了一些变种,但都没有成功。

其中一个:

(defun calcPrefInf (a b c)
  (funcall b a c))

5 个答案:

答案 0 :(得分:12)

好的,让我们这样做只是为了好玩。首先,让我们定义操作的优先顺序,因为当一个人处理中缀表示法时,这是必要的。

(defvar *infix-precedence* '(* / - +))

非常好。现在想象我们有一个函数to-prefix,它将中缀符号转换为抛光前缀表示法,因此Lisp可以处理它并计算出一些事情。

让我们编写简单的reader-macro来包含我们对to-prefix的调用,以及审美的原因:

(set-dispatch-macro-character
 #\# #\i (lambda (stream subchar arg)
           (declare (ignore sub-char arg))
           (car (reduce #'to-prefix
                        *infix-precedence*
                        :initial-value (read stream t nil t)))))

现在,让我们编写一个非常简单的函数to-prefix,它将在给定符号的给定列表中将中缀表示法转换为前缀表示法。

(defun to-prefix (lst symb)
  (let ((pos (position symb lst)))
    (if pos
        (let ((e (subseq lst (1- pos) (+ pos 2))))
          (to-prefix (rsubseq `((,(cadr e) ,(car e) ,(caddr e)))
                              e
                              lst)
                     symb))
        lst)))

好,好。函数rsubseq可以定义为:

(defun rsubseq (new old where &key key (test #'eql))
  (labels ((r-list (rest)
             (let ((it (search old rest :key key :test test)))
               (if it
                   (append (remove-if (constantly t)
                                      rest
                                      :start it)
                           new
                           (r-list (nthcdr (+ it (length old))
                                           rest)))
                   rest))))
           (r-list   where)))

现在是时候尝试了!

CL-USER> #i(2 + 3 * 5)
17
CL-USER> #i(15 * 3 / 5 + 10)
19
CL-USER> #i(2 * 4 + 7 / 3)
31/3
CL-USER> #i(#i(15 + 2) * #i(1 + 1))
34

答案 1 :(得分:2)

如果你想让它适用于像(2 + 3 * 5 / 2.4)这样的复合表达式,最好把它转换成正确的前缀表达式,然后对它进行评估。您可以在这里找到一些很好的代码示例:http://www.cs.berkeley.edu/~russell/code/logic/algorithms/infix.lisp或Piter Norvigs "Paradigs of Artificial Intelligence Programming"。这里的代码示例:http://www.norvig.com/paip/macsyma.lisp

它太长了,无法张贴在aswer上。

答案 2 :(得分:1)

“评估中缀表达式”的另一种方法是使用“可读”库直接在Common Lisp阅读器中启用中缀读取,然后让用户使用该表示法。然后实现传统的Lisp评估器(或者只是直接评估,如果您信任用户)。

假设您启用了QuickLisp,请使用:

(ql:quickload "readable")
(readable:enable-basic-curly)

现在,用户可以输入任何中缀表达式{a op b op c ...},其可读性自动映射到“(op a b c ...)”。例如,如果用户输入:

{2 + 3}

读者将返回(+ 2 3)。现在你可以使用:

(eval (read))

显然,如果用户可能是恶意的,请不要使用“eval”。在这种情况下,实现一个按照您希望的方式评估值的函数。

这里的教程: https://sourceforge.net/p/readable/wiki/Common-lisp-tutorial/

答案 3 :(得分:0)

假设您正在使用lisp2方言,您需要确保在查找函数名称空间中要使用的函数(使用#'f (function f)否则,它会在变量名称空间中查找,不能在funcall中使用。

所以有了定义:

(defun calcPrefInf (a b c)
    (funcall b a c))

您可以将其用作:

(calcPrefInf 2 #'+ 3)

答案 4 :(得分:0)

您可以尝试enter image description here

(nfx 1 + (- x 100)) ;it's valid!
(nfx 1 + (- x (3 * 3))) ;it's ALSO valid!
(nfx 1 + (- x 3 * 3)) ;err... this can give you unexpected behavior