來自我在Stack Overflow上的提問,https://stackoverflow.com/questions/51675355/how-to-eval-a-cond-case-and-return-function-object前端
(hy做者回復真及時,可是以前在github issue裏提問就被拒了 哈哈哈)python
個人問題是,我須要本身組裝 帶有條件表達式(cond [p e]) 。git
p多變,而e基本不變。所以但願和gcc編譯到中間語言RTL同樣,在RTL層作點優化,部分求值。github
準確的說,先把e求值求出來,個人e語句的求值結果是function object函數
而後在時節1裝入 條件語句p優化
在時節2 對(cond [p e]) 用eval求值,就直接獲得 想要的函數對象了spa
代碼大概這樣code
;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>blog
做者的解釋說
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 啊
我還得消化一下。。