来自我在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 啊
我还得消化一下。。
原文地址:https://www.cnblogs.com/xuanmanstein/p/9417464.html