定义用于在Lisp中计算中缀表达式的函数

定义用于在Lisp中计算中缀表达式的函数,lisp,common-lisp,infix-notation,Lisp,Common Lisp,Infix Notation,我不是很擅长Lisp,我需要做一个函数,允许计算中缀表达式。例如:(+23)->(infixFunc 2+3)。我尝试了一些变体,但没有一个成功 其中一项: (defun calcPrefInf (a b c) (funcall b a c)) 假设使用的是lisp2方言,则需要确保在函数名称空间中查找要使用的函数(通过使用(函数f))的#f。否则将在变量名称空间中查找该函数,并且不能在funcall中使用 因此,有了定义: (defun calcPrefInf (a b c) (

我不是很擅长Lisp,我需要做一个函数,允许计算中缀表达式。例如:
(+23)->(infixFunc 2+3)
。我尝试了一些变体,但没有一个成功

其中一项:

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

假设使用的是lisp2方言,则需要确保在函数名称空间中查找要使用的函数(通过使用
(函数f)
)的
#f
。否则将在变量名称空间中查找该函数,并且不能在funcall中使用

因此,有了定义:

(defun calcPrefInf (a b c)
    (funcall b a c))
您可以将其用作:

(calcPrefInf 2 #'+ 3)

如果您希望它适用于(2+3*5/2.4)等复合表达式,最好将其转换为适当的前缀表达式,然后对其进行求值。您可以在此处或在Piter Norvigs的书中找到一些进行这种转换的代码示例。代码示例如下:


它实在太长了,无法在aswer中发布。

好吧,让我们只是为了好玩。首先,让我们定义操作的优先顺序,因为当我们处理中缀符号时,这是必要的

(defvar *infix-precedence* '(* / - +))
很好。现在假设我们有一个函数
to prefix
,它将中缀表示法转换为波兰前缀表示法,这样Lisp就可以处理它并计算出一些东西

为了美观起见,让我们编写一个简单的reader宏,将调用
的过程包装为前缀

现在,让我们编写一个非常简单的函数
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
等等。

另一种“计算中缀表达式”的方法是使用“可读”库在公共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”。在这种情况下,请实现一个函数,以您希望的方式计算值

此处有教程: 你可以试试


你为什么需要这样做?我的意思是解析然后计算中缀表达式是很常见的,但是在Lisp S-expr中混合中缀就不那么常见了(但请参见1970年代Lisp的M-expr)。@BasileStrynkevitch,我需要它来获得一点Lisp编程经验-这对
2+3*5
(计算到17)有效吗?不,这是一个更广泛的问题,因为您还必须考虑优先级等。那么我知道它没有回答问题。OP想要计算中缀表达式。2+3*5是由两个中缀表达式组成的复合表达式。它比OP想要的多
(eval (read))
(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