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)),也需要像这样的向量绑定->[]这是一个最小的示例-我希望能够将vectorseq 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)))