python + lisp hy的新手注记2 eval, HyModel and python AST

来自我在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 啊

我还得消化一下。。 

 

posted @ 2018-08-04 09:39  永远的幻想  阅读(262)  评论(0编辑  收藏  举报