Common lisp 公共lisp和中缀包

Common lisp 公共lisp和中缀包,common-lisp,eval,infix-notation,Common Lisp,Eval,Infix Notation,有一个通用lisp的中缀包(请参阅),它将中缀形式转换为前缀 例如: (string->prefix "1+2") ;; => (+ 1 2) 它还提供了reader宏#I,它可以计算中缀形式,例如 #I(1+2) ;; => 3 但我不想使用这个读卡器宏 我编写了一个简单的函数,它使用cl-ppcre将字符串替换为数字,即 (prepare-form "1+x*x" "x" 3) ;; => "1+3*3" 最后,我有一个计算中缀形式的函数 (defun eval

有一个通用lisp的中缀包(请参阅),它将中缀形式转换为前缀

例如:

(string->prefix "1+2") ;; => (+ 1 2)
它还提供了reader宏#I,它可以计算中缀形式,例如

#I(1+2) ;; => 3
但我不想使用这个读卡器宏

我编写了一个简单的函数,它使用cl-ppcre将字符串替换为数字,即

(prepare-form "1+x*x" "x" 3) ;; => "1+3*3"
最后,我有一个计算中缀形式的函数

(defun eval-infix (form &rest args)
  (eval (string->prefix (apply #'prepare-form form args))))
函数eval infix是否可以在不使用eval函数的情况下实现? 我的最终目标是这样调用eval infix:

(eval-infix "1+x*x" "x" (+ 1 2))

我想你想用的是
string->prefix
。这将实习符号,以避免污染您自己的包让定义一个。最后,您可以通过定义自己的eval来避免eval的安全问题。还有一个问题,其他软件包中的符号可以写出来,这让我很难过。还有一个问题是,中缀读取器可以转义到Lisp读取器,后者可以执行任意计算。下面是解决方案各部分的示意图。我可能把一些函数的参数按错误的顺序排列

(defpackage infix-vars)
(defun read-infix-string (s) (let ((*package* (find-package "INFIX-VARS"))) (string->prefix s)))
(defun substitute-var (expr v val)
   (let ((v (etypecase v (symbol v) (string (intern v (find-package "INFIX-VARS"))))))
    (subst expr v val)))
(defun eval-expr (e)
  (etypecase e
    (number e)
    (list
      (ecase (car e)
        (+ (apply #'+ (mapcar #'eval-expr (cdr e))))))))

我想你想用的是
string->prefix
。这将实习符号,以避免污染您自己的包让定义一个。最后,您可以通过定义自己的eval来避免eval的安全问题。还有一个问题,其他软件包中的符号可以写出来,这让我很难过。还有一个问题是,中缀读取器可以转义到Lisp读取器,后者可以执行任意计算。下面是解决方案各部分的示意图。我可能把一些函数的参数按错误的顺序排列

(defpackage infix-vars)
(defun read-infix-string (s) (let ((*package* (find-package "INFIX-VARS"))) (string->prefix s)))
(defun substitute-var (expr v val)
   (let ((v (etypecase v (symbol v) (string (intern v (find-package "INFIX-VARS"))))))
    (subst expr v val)))
(defun eval-expr (e)
  (etypecase e
    (number e)
    (list
      (ecase (car e)
        (+ (apply #'+ (mapcar #'eval-expr (cdr e))))))))

1) 为什么您想避免eval,但可以调用eval中缀?2) 您希望eval infix适用于所有CL表单还是语言的子集?1)因为我不希望eval infix具有与eval相同的安全问题。2) 最理想的情况是,eval中缀应该在语言的(数学)子集上工作。3) 基本上,我很困惑,因为在中缀包中没有看到对eval函数的调用。我怀疑它隐藏在“设置分派宏字符”中。如果没有,那么它将在不调用eval的情况下实现,这正是我想要成功的。中缀包不需要调用
eval
,因为reader宏在读取时将中缀语法转换为前缀,因此它将被编译,就好像中缀不存在一样。您必须使用宏或读取器宏,而不是函数来执行相同的操作。但是请注意,在宏扩展时将值替换到字符串中是不起作用的,因为这些值只在运行时已知。无论如何,使用字符串替换来生成代码是一件非常值得怀疑的事情。相反,您应该让生成的代码像往常一样引用变量。如果字符串在编译时不知道,并且字符串不完全可信,您也可以为安全的数学语言编写一个解释器,而不是试图将其转换为CL。非常感谢您的解释!我将eval infix作为一个宏启动,但我还希望有(eval infix“1+x*x”“x”(+12))的可能性,因此我将其更改为使用eval的函数。1)为什么要避免eval,但可以调用eval infix?2) 您希望eval infix适用于所有CL表单还是语言的子集?1)因为我不希望eval infix具有与eval相同的安全问题。2) 最理想的情况是,eval中缀应该在语言的(数学)子集上工作。3) 基本上,我很困惑,因为在中缀包中没有看到对eval函数的调用。我怀疑它隐藏在“设置分派宏字符”中。如果没有,那么它将在不调用eval的情况下实现,这正是我想要成功的。中缀包不需要调用
eval
,因为reader宏在读取时将中缀语法转换为前缀,因此它将被编译,就好像中缀不存在一样。您必须使用宏或读取器宏,而不是函数来执行相同的操作。但是请注意,在宏扩展时将值替换到字符串中是不起作用的,因为这些值只在运行时已知。无论如何,使用字符串替换来生成代码是一件非常值得怀疑的事情。相反,您应该让生成的代码像往常一样引用变量。如果字符串在编译时不知道,并且字符串不完全可信,您也可以为安全的数学语言编写一个解释器,而不是试图将其转换为CL。非常感谢您的解释!我将eval infix作为一个宏启动,但我还希望有(eval infix“1+x*x”“x”(+12))的可能性,因此我将其更改为使用eval的函数。可以编写其他包中的符号:您可以将冒号字符绑定到可读表中的错误函数(非终止-p设置为NIL)@coredump。人们可能也希望对
做同样的事情(escape to Lisp)可以编写其他包中的符号:可以将冒号字符绑定到可读表中的错误函数(非终止-p设置为NIL)@coredump。人们可能也希望对
做同样的事情(转义到Lisp)