为什么Clojure中的list *仅在尾部位置使用矢量?

时间:2018-08-15 17:06:42

标签: clojure

我是Clojure新手。我正在尝试玩repl,并且看到以下内容作为输出。而且我不太明白为什么每个人的行为如此不同

(def a (list 1 2 3))  =>#'test.core/a

(list* 4 5 a)          =>(4 5 1 2 3)

(list* a 4 5)         =>IllegalArgumentException Don't know how to create ISeq from: java.lang.Long  clojure.lang.RT.seqFrom (RT.java:542)

为什么上面2条语句在上面2条语句中的行为相同?

(list* 4 5 [1 2 3])     =>(4 5 1 2 3)

(list* 4 5 [a])       =>(4 5 (1 2 3))

(list* 4 5 (1 2))     =>ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn  test.core/eval3837 (form-init633779145118520639.clj:1)

有人可以解释为什么以上每个语句都有不同的输出吗?

2 个答案:

答案 0 :(得分:4)

如果您查看definition和文档字符串,这将很有意义。

文档说:

  

“创建一个新序列,其中包含其余项目之前的项目,最后一个项目将被视为一个序列。”

强调我的。

在第一个块中,最后一个表达式失败,因为5是最后一个参数,但不是序列。

(list* 4 5 [1 2 3])起作用的原因与(list* 4 5 a)起作用的原因相同。正如预期的那样,最后一个参数是一个序列。正如您在定义中看到的那样,它仅cons到达最后一个参数。

(list* 4 5 [a])给出不同的结果,因为您已将集合a包装在另一个集合中。它只是添加到外部集合,而保持内部不变。

(list* 4 5 (1 2))的失败并不是真正的相关问题。请记住,每当您将(...)取消引用时,它将尝试对其进行评估,并且期望列表中的第一个元素是可调用的。但是1是不可调用的,因此是错误。您需要用引号将其视为列表文字,而不是要评估的代码。

答案 1 :(得分:2)

请参阅文档字符串以获取列表*:

  

创建一个新的seq,其中包含前面其余的项目,最后一个   其中将被视为一个序列。

请注意,seq不是列表,而是列表和向量以及其他事物可以视为序列。当在repl上输出时,seq看起来也像一个列表-打印在parens中。

因此,在第一种情况下,您的最后一个参数是文字向量,将其视为序列,您将获得未嵌套的序列。

在第二种情况下,您将列表“ a”作为文字向量中的单个元素,因此该向量被视为一个序列,但内部列表则未被视为,返回的序列长为三个元素:4、5和列表a。

在最后一种情况下,您将使用lisps中的函数调用语法,该语法与列表语法非常相似。 (1 2)试图像在函数中一样调用数字1(带有参数2)。文字数字不能解释为函数。

如果您希望列表文字不是函数调用,则必须将其引号:

(list* 4 5 '(1 2)) => (4 5 1 2)