我在Lisp中不是很好,我需要做一个允许评估中缀表达式的函数。例如:(+ 2 3) -> (infixFunc 2 + 3)
。我尝试了一些变种,但都没有成功。
其中一个:
(defun calcPrefInf (a b c)
(funcall b a c))
答案 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)