代码之家  ›  专栏  ›  技术社区  ›  OlegTheCat

为什么在case/ecase中nil不能匹配?

  •  3
  • OlegTheCat  · 技术社区  · 6 年前

    以下表格

    (let ((foo nil))
      (ecase foo
        (:bar 1)
        (:baz 2)
        (nil 3)))
    

    投掷误差 NIL fell through ECASE expression . 解决这个问题的方法似乎是 nil 带括号的大小写,如下所示:

    (let ((foo nil))
      (ecase foo
        (:bar 1)
        (:baz 2)
        ((nil) 3))) ;; => 3
    

    但为什么第一个例子行不通呢?打开包装 案例有什么特别的意义?

    1 回复  |  直到 6 年前
        1
  •  8
  •   Barmar    6 年前

    每一条款 case 可以与单个项目或项目列表匹配,例如,您可以编写:

    (ecase foo
      (:bar 1) ;; match a specific symbol
      ((:baz :quux) 2)) ;; match either of these symbols
    

    NIL 也是lisp中的空列表,当它用作 案例 这就是它的处理方式,所以它从不匹配任何东西。同样地, T OTHERWISE 用于指定默认大小写,因此不能将它们作为单个项进行匹配。要匹配其中任何一个,您需要将它们放在一个列表中。

    从技术上讲, specification 这是关于子句中的键的:

    钥匙 ---对象列表的指示符。在这种情况下,符号 t otherwise 不能用作键指示符。把这些符号本身称为键 (t) (otherwise) 必须分别使用。

    以及a的定义 list designator 说:

    对象列表的指示符;也就是说,表示一个列表的对象,它是一个非零原子(表示元素为非零原子的单例列表)或一个适当的列表(表示自身)之一。

    注意,单原子被视为单原子列表的情况称为“非零原子”。这允许 属于第二种情况,其中一个适当的列表表示它自己。否则,将无法为空列表创建列表指示符,因为 将表示 (NIL) .

    你可能会争辩说,在 CASE 因为它永远不会匹配任何内容,整个子句可以省略。这种退化的情况是为了自动生成代码(例如,扩展到 案例 ,因为它们可能会生成空列表,所以应该与其他列表一致地处理这些列表。对于他们来说,很难让子句的生成以是否有任何键为条件。