替代if语句的层

时间:2012-09-27 12:56:27

标签: if-statement lisp boolean conditional

有时我会在我的lisp代码中使用if语句层。这样做还有其他选择吗?

2 个答案:

答案 0 :(得分:4)

这是其中一个案例,不幸的是,答案是“它取决于”。在某些情况下,显而易见的选择是使用cond

(if condition1
   result1
   (if condition2
       result2
       default))

;; naturally converted to:
(cond (condition1 result1)
      (condition2 result2)
      (t default))

其他时候,condorand配对可能正是您想要的。

(if condition1
   (if condition2
       result12
       result1)
   (if condition2
       result2
       default))

;; naturally turns intoteh answe
(cond ((and condition1 condition2) result12)
      (condition1 result1)
      (condition2 result2)
      (t default))

注意,我只编写了代码,但未经过测试,但原则上应该没问题。

不幸的是,有时甚至有些简单易读的cond形式也不够清晰,在这种情况下,通常值得盯着实际问题稍微努力一点。可能有一种方法可以更好地分解逻辑(调度表,外部逻辑调用具有合适参数的函数,......)。

答案 1 :(得分:2)

您可以通过几个方向更改代码。

  1. 创建封装条件的高阶函数,或者可能是宏,或者可能重用现有的宏(例如,查看at case macro)。 remove-if将是一个高阶函数的示例,可以帮助您编写“if”。

  2. 使用多态。 Lisp具有类,对象,重载以及您期望对象系统具有的所有检测(可能甚至更多一些;)。

  3. 假设您有以下代码:

    ;; Suppose your `person' is a list that has that person's
    ;; name as its first element:
    
    (defun hello! (person)
      (if (string= (car person) "John")
            (concatenate 'string "Hello, " (car person))
         (print "Hello, who are you?")))
    
    (defun goodbye! (person)
      (if (string= (car person) "John")
            (concatenate 'string "Goodbye, " (car person))
         (print "Goodbye, mysterious stranger!")))
    
    ;; You would use it like so:
    (hello! '("John" x y z))
    (goodbye! '(nil x y z))
    

    现在,您可以将其重写为:

    (defclass person () ())
    
    (defclass friend (person)
      ((name :accessor name-of
             :initarg :name)))
    
    (defgeneric hello! (person))
    (defgeneric goodbye! (person))
    
    (defmethod hello! ((person person))
      (print "Hello, who are you?"))
    
    (defmethod hello! ((person friend))
      (print (concatenate 'string "Hello, " (name-of person))))
    
    (defmethod goodbye! ((person person))
      (print "Goodbye, mysterious stranger!"))
    
    (defmethod goodbye! ((person friend))
      (print (concatenate 'string "Goodbye, " (name-of person))))
    
    ;; Which you would use like so:
    
    (hello! (make-instance 'person))
    (goodbye! (make-instance 'friend :name "John"))
    
    ;; Note that however the later is significantly more verbose
    ;; the ratio will change when you have more `if's which you
    ;; can systematize as objects, or states.
    

    换句话说,通过封装状态,您可以避免显式写入条件语句。你也可以在途中获得一些可读性,因为你不需要记住列表中的哪一部分包含哪些信息 - 你现在可以将它标记为“名称”。