Clojure 将seq exprs传递给以使用报价

Clojure 将seq exprs传递给以使用报价,clojure,Clojure,我试图使用引号将seq exprs传递给for,但我下面的两次尝试都导致compilereException java.lang.IllegalArgumentException:for需要一个用于其绑定的向量。我显然误解了引用和评估(以及相关概念)的工作原理 正确的方法是什么?您将如何向Beginer解释为什么上面的实现都不起作用?谢谢 编辑: 我知道我能行 (let [] (for [b (range 2)] b)) 我试图实现的是能够传递绑定向量(例如,另一个函数的输出) 编辑2,

我试图使用引号将
seq exprs
传递给
for
,但我下面的两次尝试都导致
compilereException java.lang.IllegalArgumentException:for需要一个用于其绑定的向量
。我显然误解了引用和评估(以及相关概念)的工作原理

正确的方法是什么?您将如何向Beginer解释为什么上面的实现都不起作用?谢谢

编辑:
我知道我能行

(let []
   (for [b (range 2)] b))
我试图实现的是能够传递绑定向量(例如,另一个函数的输出)

编辑2,动机/背景:
我正在构建一个transpiler[]并尝试转换和展开for循环(包括嵌套循环),因此我认为可以在通过嵌套循环深入遍历AST(抽象语法树)的同时,将要迭代的变量范围附加到
seq exprs
,然后评估转换后的关系如果clojure
生成了“绑定”,则每个原始块中包含的(关系始终可以逐个转换)。如果有“更好”的方法,您有什么建议吗?

['b(范围2)]=>['b(0 1)]
在本例中,您有一个名为
b
的符号,并且您正在调用函数
(范围2)
,该函数求值
(01)

'[b(范围2)]=>[b(范围)]
在本例中,您引用了所有表达式,因此在列表数据结构中有符号
b
范围符号

关于for循环,您会得到该异常,因为您没有正确使用它(缺少向量绑定)

以下是编写for循环的方法:

(for [i (range 5)] ;;you need to define vector in here
     (do 
         (println "I: " i) 
         i));;let's return i here
结果:

I: 0
I: 1
I: 2
I: 3
I: 4
=> (0 1 2 3 4)

这正是宏和函数之间的区别。函数在运行时获取并返回数据。然而,宏在编译时获取并返回代码

考虑以下几点:

(defn foo [arg]
  (str arg))

(let [x (dec 10)]
  (foo x)) ;=> "9"
foo
将整数9视为参数,因为
x
的当前运行时值为9。但是,
foo
无法知道值9由符号
x
表示,因为符号
x
是代码

(defmacro bar [arg]
  (str arg))

(let [x 9]
  (bar x)) ;=> "x"

(str 'x) => "x"
因此,如果我们将其更改为宏,我们将得到编译时值
x
,它只是符号
x

(我们将其更改为字符串,然后将其作为代码返回,而字符串
“x”
作为代码仅计算为
“x”

这里重要的一点是,同样的
foo
无法知道它被传递了一个名为
x
的东西,它只知道运行时值是9,
bar
只知道它被传递了一个名为
x
的东西,它无法知道
x
的运行时值是什么

这就是宏具有传染性的原因

因此,在您的示例中,
v
的运行时值是
'[b(范围2)]
,但传递给
的编译时值只是符号
v
本身

为了解决眼前的问题,您可以采取以下措施:

(let [v '[b (range 2)]]
  (eval `(for ~v ~'b)))
但这太可怕了。你可能想写一个宏

我不确定这个宏会是什么样子,因为我必须理解您想要解决的实际问题,但这里有一个宏示例,它接受seq expr并将它们传递给
for

;; Minimal example of a macro that takes seq-exprs as code
;; and returns code with a for that uses them.
(defmacro forv [seq-exprs body]
  `(vec (for ~seq-exprs ~body)))

最后你想得到这样的东西:(对于[i(01)]?你想实现什么?你可以这样使用:(对于[i(范围2)](println“i is:”i)),也需要像这样的向量绑定->[]这是一个最小的示例-我希望能够将vector
seq exprs
作为变量传递给
for
。因为
for
是一个宏,它在编译时展开,这意味着绑定向量应该是一个文本向量,而不是一个变量,所以您尝试做的是完全不可能的(编译器只是不知道
v
)的运行时值。您可以使用另一个宏返回
用于
宏(它仍然无法对
v
的运行时值进行操作)或者你可以使用
eval
,这是不好的。你为什么要这样做呢?
for
生成一个序列。如果你总是要将参数向量传递给
for
,为什么不将
for
生成的序列传递给你想要使用它的任何东西呢?我不知道“可能”这个词。问这个问题的人通常想要笛卡尔乘积之类的东西,最好是作为一个函数,获取列表列表并返回元组列表。这很有意义。@madstap我想知道如何使用你提供的宏来解决问题,但我不能,你能给我举个例子吗?我已经试过了按照以下方式
(让[v'[b(范围2)]主体“b](宏扩展(for v body))
并获得
(clojure.core/vec(clojure.core/for v body))
。正如您所解释的,宏不会计算参数的运行时值,因此我不知道如何通过编写宏来解决这个问题。@我编写的宏是作为一个接受seq expr并返回使用它们的代码的宏的最小示例,如果不清楚,很抱歉。我无法提供解决方案作为一个宏打开,因为我不知道您想要什么。您的最小示例是.1/2值
'[b(范围2)]
仅在运行时存在,到那时,
for
已经获取了它的参数并返回了基于这些参数的代码。要真正执行您所说的操作,我上面描述了
eval
舞蹈“可怕”,但如果你退一步,问自己几次“为什么”,几乎可以肯定有一个更简单、更容易的解决方案。2/2
;; Minimal example of a macro that takes seq-exprs as code
;; and returns code with a for that uses them.
(defmacro forv [seq-exprs body]
  `(vec (for ~seq-exprs ~body)))