我是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)
有人可以解释为什么以上每个语句都有不同的输出吗?
答案 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)