测试将结构编译为类函数列表的高阶函数
我有一个这样的地图(可以使用通常的布尔运算符嵌套,使用模块“布尔”和“数据”将包含适当的值,例如“左”,“右”和“运算符”将是“和” ,“or”,“not”):
{ "data" { "name" "lang", "operator" "=", "value" "blue" },
"module" "impression_hint"}
我想要的是一个返回一个列表的函数,该列表可以插入到(fn [context] ...)列表中,在那里它将能够针对我们将抛出的内容执行在它。
考虑到上述结构,插值到函数中后的最终结果应该是这样的:
(fn [context]
(= ((context :impression_hint) "lang") "blue"))
因此,我的解析/编译函数必须只返回 (= ...) 部分。我有一些非常接近的东西:
(defn- parse-internal [tree acc]
(cond
; other cases will go here
(= "impression_hint" (tree "module"))
(let [data (tree "data")
op (data "operator")
name (data "name")
value (data "value")]
`(~(symbol op) ((context :impression_hint) ~name) ~value))
:else
(throw (RuntimeException. (str "Unknown module: " (tree "module"))))))
在我的测试中,这返回:
FAIL in (simple-shallow-rules-generate-simple-shallow-functions) (targeting.clj:10)
expected: (= (quote (= ((context :impression_hint) "name") "blue")) (bloom.adgear.targeting/parse {"data" {"name" "lang", "operator" "=", "value" "blue"}, "module" "impression_hint"}))
actual: (not (= (= ((context :impression_hint) "lang") "blue")
(= ((bloom.adgear.targeting/context :impression_hint) "lang") "blue")))
注意到上下文参数?它已命名,这就是导致我的测试失败的原因。我确信我可以做一些事情,但是调用符号会导致符号未定义,这是有道理的,因为该符号尚不存在。
关于 acc 参数:我怀疑我最终会从此函数中删除递归,并使用 acc 进行递归,将我的返回值放入累加器中。不过,这还有些遥远。
I have a map such as this (which can be nested using the usual boolean operators, using module "boolean" and "data" would contain appropriate values, such as "left", "right" and "operator" would be "and", "or", "not"):
{ "data" { "name" "lang", "operator" "=", "value" "blue" },
"module" "impression_hint"}
What I want is a function that returns a list which can be interpolated in a (fn [context] ...) list, where it will be able to execute against what we'll throw at it.
Given the above structure, the final result, after being interpolated into a function, should be something like this:
(fn [context]
(= ((context :impression_hint) "lang") "blue"))
Thus, my parsing/compiling function must only return the (= ...) part. I have something which is tantalizingly close:
(defn- parse-internal [tree acc]
(cond
; other cases will go here
(= "impression_hint" (tree "module"))
(let [data (tree "data")
op (data "operator")
name (data "name")
value (data "value")]
`(~(symbol op) ((context :impression_hint) ~name) ~value))
:else
(throw (RuntimeException. (str "Unknown module: " (tree "module"))))))
In my test, this returns:
FAIL in (simple-shallow-rules-generate-simple-shallow-functions) (targeting.clj:10)
expected: (= (quote (= ((context :impression_hint) "name") "blue")) (bloom.adgear.targeting/parse {"data" {"name" "lang", "operator" "=", "value" "blue"}, "module" "impression_hint"}))
actual: (not (= (= ((context :impression_hint) "lang") "blue")
(= ((bloom.adgear.targeting/context :impression_hint) "lang") "blue")))
Notice the context parameter? It's been namespaced, and this is what is making my test fail. I'm certain I can do something, but calling symbol results in a symbol not defined, which makes sense since the symbol doesn't exist yet.
Regarding the acc parameter: I suspect I'll remove recursion from this function, eventually, and recur using acc, cons'ing my return value onto the accumulator. That's a bit further down the road though.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题在于,语法引用形式(前面带有反引号)中的无命名空间文字符号会根据语法引用形式在词汇上出现的位置填充命名空间组件。您的问题似乎出现在定义
bloom.adgear.targeting
命名空间的文件中,因此这就是附加到context
的内容。大多数时候,这是一个很酷的功能,但是当您需要避免它时,您可以使用
~'
技巧:波浪号取消引用下一个形式,因此它不受语法影响 -引用的魔力(包括自动解析符号);但随后它会被求值,因此需要引用,以便您返回原始形式(符号
foo
),而不是它的值(无论foo
当前绑定到什么)。The problem is that namespace-less literal symbols in syntax-quoted forms (those preceded with a backtick) get the namespace component filled in based on where the syntax-quoted form lexically appears. Yours would appear to occur in the file where the
bloom.adgear.targeting
namespace is defined, so that's what gets attached tocontext
.Most of the time, this is a cool feature, but when you need to avoid it, you can use the
~'
trick:The tilde unquotes the next form, so it isn't affected by syntax-quote's magic (including autoresolving symbols); but then it gets evaluated, so the quote is needed so you get back your original form (the symbol
foo
) and not its value (whateverfoo
is bound to currently).