测试高阶函数,将结构编译为类似函数的列表

时间:2010-12-18 13:16:00

标签: compiler-construction clojure higher-order-functions

我有一个这样的地图(可以使用通常的布尔运算符嵌套,使用模块“boolean”和“data”将包含适当的值,例如“left”,“right”和“operator”将是“和”,“或”,“不是”):

{ "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重复,将我的返回值输入累加器。不过,这有点远了。

1 个答案:

答案 0 :(得分:1)

问题在于语法引用形式(带有反引号的那些)中没有名称空间的文字符号会根据词法出现的语法引用形式获取填充的名称空间组件。您的内容似乎发生在定义bloom.adgear.targeting命名空间的文件中,因此附加到context的内容。

大多数情况下,这是一个很酷的功能,但是当你需要避免它时,你可以使用~'技巧:

`foo
; => some-ns/foo
`~'foo
; => foo

代字号取消引用下一个表单,因此它不受语法引用的魔法(包括自动分解符号)的影响;但随后它会被评估,因此需要引用以便您返回原始表单(符号foo)而不是其值(无论当前绑定foo)。