1

函数 "greaterthan",(< NUM1 NUM2)只允许返回 t/nil 来比较 2 个值。

我想测试 (var1 > var2 < var3 < var4),有没有办法只使用 lisp 中的一个函数来做到这一点?如果不是,最好的程序是什么?

4

4 回答 4

6

最好的程序是不要打扰:(and (< var2 var1) (< var2 var3) (< var3 var4))不是更难阅读您的..>..<..<..链条。

测试升序是有意义的:

(require 'cl)
(defun cl-< (&rest args)
   (every '< args (cdr args))

这些天我不再犹豫(require 'cl)了,但如果你这样做了,这里有另一个变体:

(defun cl-< (arg &rest more-args)
  (or (null more-args)
      (and (< arg (first more-args))
           (apply #'cl-< more-args))))
于 2013-02-10T22:35:06.763 回答
2

下面是variadic的宏实现<

(defmacro << (x y &rest args)
  (if args
      (if (or (symbolp y)
              (numberp y))
          `(and (< ,x ,y) (<< ,y ,@args))
          (let ((ys (make-symbol "y")))
            `(let (,ys)
               (and (< ,x (setq ,ys ,y))
                    (<< ,ys ,@args)))))
      `(< ,x ,y)))

对于简单的情况,只是扩展到(and ...)

(<< x y z) ==> (and (< x y) (< y z))

其中表达式不是数字也不是符号扩展为更复杂的形式以避免在存在副作用的情况下进行多次评估

(<< (f x) (g y) (h z)) ==> (let ((gy)) (and (< (f x) (setq gy (g y)))
                                            (< gy (h z))))

例如

(setq foo (list))
nil

(defun call (x) (push x foo) x)
call

(<< (call 1) (call 2) (call 5) (call 4) (call 0))
nil

foo
(4 5 2 1)

每个函数都被调用了一次,除了0因为短路而不需要调用的函数(我不是 100% 确定短路是否是一个真正的好主意......#'<在 Common Lisp 中是一个常规函数所有参数都按从左到右的顺序精确计算一次,没有短路)。

于 2013-02-11T08:57:55.170 回答
0
(defun << (arg1 arg2 arg3 arg4)
 (when (and (< arg1 arg2) (< arg2 arg3) (< arg3 arg4)))
)

(<< 1 2 3 4)

可能可以用任意数量的参数进行扩展,但这样的一般形式似乎很有用。

于 2013-02-11T07:15:49.977 回答
0
(defmacro << (&rest args)
  (let ((first (car args))
        (min (gensym))
        (max (gensym))
        (forms '(t)) iterator)
    (setq args (reverse (cdr args))
          iterator args)
    `(let ((,min ,first) ,max)
       ,(or 
         (while iterator
           (push `(setq ,min ,max) forms)
           (push  `(< ,min ,max) forms)
           (push `(setq ,max ,(car iterator)) forms)
           (setq iterator (cdr iterator))) `(and ,@forms)))))

(macroexpand '(<< 10 20 30 (+ 30 3) (* 10 4)))
(let ((G99730 10) G99731)
  (and (setq G99731 20)
       (< G99730 G99731)
       (setq G99730 G99731)
       (setq G99731 30)
       (< G99730 G99731)
       (setq G99730 G99731)
       (setq G99731 (+ 30 3))
       (< G99730 G99731)
       (setq G99730 G99731)
       (setq G99731 (* 10 4))
       (< G99730 G99731)
       (setq G99730 G99731) t))

这是类似于 6502 的想法,但它可能会在不那么琐碎的情况下创建更少的代码,但它会在琐碎的情况下创建更多的代码。

于 2013-02-12T06:35:07.657 回答