我如何构建这个lisp宏?

时间:2016-05-30 23:40:56

标签: macros lisp common-lisp

我正在通过l99为lisp学习lisp。

这是来自here,我希望只为练习应用宏,用宏写出所有((x) (x (evaluate-boolean left bindings) (evaluate-boolean right bindings)))

(defun evaluate-boolean (expression bindings)
  "Evaluates the boolean expression. Returns t or nil

expression := variable 
            | constant 
            | '(' operator expression expression ')' 
            | '(' not expression ')'
            .
constant := 'true' | 'fail' .
variable := symbol .
operator := 'and' | 'or' | 'nand' | 'nor' | 'xor' | 'impl' | 'equ' .

bindings is a list of pairs (variable . constant)
"
  (cond ((eq expression 'true) t)
        ((eq expression 'fail) nil)
        ((symbolp expression)
         (let ((pair (assoc expression bindings)))
           (if pair
               (progn
                 (assert (member (cdr pair) '(true fail)))
                 (eql 'true (cdr pair)))
               (error "No variable named ~A in the bindings." expression))))
        ((atom expression) (error "Invalid atom ~A in the expression." expression))
        (t (case (length expression)
             ((2) (destructuring-bind (op subexpression) expression
                    (case op
                      ((not) (not (evaluate-boolean subexpression bindings)))
                      (otherwise (error "Invalid operator ~A in ~A" op expression)))))
             ((3) (destructuring-bind (op left right) expression
                    (case op
                      ((and)  (and  (evaluate-boolean left bindings) (evaluate-boolean right bindings)))
                      ((or)   (or   (evaluate-boolean left bindings) (evaluate-boolean right bindings)))
                      ((nand) (nand (evaluate-boolean left bindings) (evaluate-boolean right bindings)))
                      ((nor)  (nor  (evaluate-boolean left bindings) (evaluate-boolean right bindings)))
                      ((xor)  (xor  (evaluate-boolean left bindings) (evaluate-boolean right bindings)))
                      ((impl) (impl (evaluate-boolean left bindings) (evaluate-boolean right bindings)))
                      ((equ)  (equ  (evaluate-boolean left bindings) (evaluate-boolean right bindings)))
                      (otherwise (error "Invalid operator ~A" op)))))
             (otherwise (error "Invalid expression ~A" expression))))))

我尝试过一些事情,但他们似乎都错误地报告了缺失的变量。

我如何实现宏

  • 作为defmacro
  • macrolet函数中使用evaluate-boolean

我通常首先使用defundefmacro测试内容,然后将其替换为flet。对此有何建议?

2 个答案:

答案 0 :(得分:4)

既然你没有说你尝试了什么我不知道你做错了什么,但我猜你可能试图用宏调用替换static内的个别情况?这不起作用,因为外部宏(CASE)在内部宏之前展开,因此内部宏不能用于生成外部宏的语法(除非专门编写外部宏以允许,这不是这里的情况。)

所以解决方案是编写一个为您生成整个CASE的宏。类似的东西:

CASE

虽然我不相信这是一个好主意。像这样的一个宏会使您的代码更难理解,这也不会显着缩短代码。通常,您会希望使用宏来抽象在代码中多次出现的模式。

更通用的方法可能是这样的:

(macrolet ((ops-case (op-sym (&rest ops))
             `(case ,op-sym
                ,@(loop for op in ops
                        collect `((,op) (,op (evaluate-boolean left bindings)
                                             (evaluate-boolean right bindings))))
                (otherwise (error "Invalid operator ~A" ,op-sym)))))
  (ops-case op (and or nand nor xor impl equ)))

这会通过用case中的值替换tempate中的下划线来生成case表达式。例如:

(defmacro ecase-template (keyform template &body cases)
  `(ecase ,keyform
     ,@(loop for case in cases
             collect (sublis `((_ . ,case)) template))))

答案 1 :(得分:1)

这可能不是你想要的,但CLOS对于这种符号发送评估来说非常棒。

以下是评估者使用一对通用函数(当然,对于您的小语言来说真的是[HttpPost("Auth/SignIn")] [ValidateAntiForgeryToken] public async Task<IActionResult> SignIn(SignInViewModel model, string returnUrl = null) { ViewData["ReturnUrl"] = returnUrl; if (ModelState.IsValid) { var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, true, false); if (result.Succeeded) { // Resolve the user via their email var user = await _userManager.FindByEmailAsync(model.Email); // Get the roles for the user var roles = await _userManager.GetRolesAsync(user); // Do something with the roles here } else { // Uh oh.... } } // Something is probably wrong, provide the form again.... return View(model); } eval)以及宏的一个(经过极少测试的)实现这可以让你定义&#39; direct&#39; apply泛型函数的方法。 A&#39;直接&#39; method是一种可以简单地翻译成涉及带有同名语言的运算符的表单的方法(这基本上涵盖了代码中所有大的嵌套apply)。

(在某些情况下,它的工作方式与您的代码略有不同:例如,一旦发现变量绑定,它就会以其值返回评估者,而不是具有任何其他特殊情况的聪明。)

case