来自我在 Stack Overflow 上的提问, https://stackoverflow.com/questions/51675355/how-to-eval-a-cond-case-and-return-function-object
(hy 作者回复真及时, 但是之前在 github issue 里提问就被拒了 哈哈哈)
我的问题是, 我需要自己组装 带有条件表达式 (cond [p e]) .
p 多变, 而 e 基本不变. 因此希望和 gcc 编译到中间语言 RTL 一样, 在 RTL 层做点优化, 部分求值.
准确的说, 先把 e 求值求出来, 我的 e 语句的求值结果是 function object
然后在时节 1 装入 条件语句 p
在时节 2 对 (cond [p e]) 用 eval 求值, 就直接得到 想要的函数对象了
代码大概这样
- ;a fn object
- (setv a_fn (fn [x] (+ 1 x)))
- ;a mock predicator
- (setv predicator True)
- ;inject predicator and a_fn into a (cond ..)
- (setv cond_expr `(cond [(~predicator) [~a_fn]]))
- ;eval at another place
- (eval cond_expr)
但是这样是报错的:
got TypeError: Don't know how to wrap <class'function'>: <function test_cond_list_fn.<locals>.<lambda> at 0x000001B879FD3D08>
作者的解释说
hy 的 eval 是 首先要编译到 python 的 ast.(类似 gcc 前端语言 编译到 RTL 的 AST)
但 "虽然可以把抽象对象放进 hyExpression, 但没法 compile it"
一方面 Hy 的 compiler 只接受 HyModel (hyExpression HyList HySymbol 还有基本类型 HyInt HyString 等等),
另一方面: 在 Python ast 里, function object 没有显式的表示法, 所以就没有对应的 HyModel (同理可知, 其他自定义的 pyObejct 也都这样了)
-- 但, 不是完全无解.
作者的给出的解决方案是, 不要 eval 含有 function object 的 hyExpression 但可以有 函数的 定义
1 compile a function definition.
- => (setv a-fn '(fn [x] (+ 1 x)))
- => (setv cond-expr `(cond [True ~a-fn]))
- => (eval cond-expr)
- <function <lambda> at 0x0000020635231598>
注意第一行是普通单引号', 不是反引号 `
2 Or a function's symbol.
- => (defn b-fn [x] (- x 1))
- => (setv cond-expr2 `(cond [True b-fn]))
- => (eval cond-expr)
- <function <lambda> at 0x0000020635208378>
Mmmm~ 到了 AST 这个层次, 还真是有点 subtle 啊
我还得消化一下..
来源: http://www.bubuko.com/infodetail-2713630.html