2011-09-08 66 views
4

我有一個python庫,它構建出nested function calls以外的特殊迭代器(行爲樹)。雖然API具有相當好的和輕量級的語法(由於它是python),但它確實可以使用聲明式DSL。將聲明式DSL翻譯爲嵌套式函數調用

這裏就是我設想的草圖:

的DSL(使用YAML):

tree: 
    - sequence: 
    - do_action1 
    - do_action2 
    - select: 
     - do_action3 
     - sequence: 
     - do_action4 
     - do_action5 
     - do_action6 

會導致以下嵌套函數調用:

visit(
    sequence(
     do_action1(), 
     do_action2(), 
     select(
      do_action3(), 
      sequence(
       do_action4(), 
       do_action5(), 
       ), 
      do_action6(), 
      ) 
     ) 
    ) 

我很難直觀地看到如何做到這一點。由於DSL必須表示一棵樹,所以簡單的深度優先遍歷似乎是合適的。但是爲了構建嵌套的函數調用,我不得不以某種方式將其從內部轉移出去。它可能涉及一些聰明的中間堆棧或一些,但我不能完全理解它。執行這種轉換的正確方法是什麼?

+0

「它真的可以用一個聲明DSL」?真?你的Python代碼比你的DSL更可讀。 DSL如何提供幫助? –

+0

在這個*非常簡單*的例子中,括號尤其是bug我。在一個更復雜的樹中,特別是當涉及到關鍵字參數時,需要子選項('** kwargs')會嚴重降低可讀性。 [鏈接到現實生活中的示例](https://github.com/eykd/owyl/blob/master/examples/boids.py#L281)演示了這一點 - 「parallel」節點的'policy'參數很容易錯過。 –

+1

如果「真實生活中的例子」實際上表明瞭問題,那麼也許你應該在這裏包括類似的東西。 DSL是一個有吸引力的麻煩。我還沒有看到一個提供任何價值。如果你有一個例子,請解決這個問題,以顯示增加複雜性的一些令人信服的理由。 –

回答

3

我想你可以讓Python跟蹤函數調用和參數,而不是用堆棧自己做。

假設您有一個YAML分析樹,其中每個節點表示一個函數調用,並且此節點的每個子節點都是一個參數(也是一個函數調用,因此它可能有自己的參數)。

然後定義功能evaluate,其評估該樹的節點,如下(僞代碼):

def evaluate(node): 
    # evaluate parameters of the call 
    params = [] 
    for child in node: 
     params.append(evaluate(child)) 

    # now make the call to whatever function this node represents, 
    # passing the parameters 
    return node.function.call(*params) 

最後,調用evaluate傳遞YAML樹的根作爲參數,你應該得到的期望的行爲。


稍有不同EVAL-應用結構

def evaluate(node): 
    # evaluate parameters of the call 
    params = [ evaluate(child) for child in node ] 

    # apply whatever function this node represents 
    return node.function.call(*params) 
+0

爲什麼會,這可能就是這樣做的。我不知道爲什麼這很難形象化。 –

+1

「爲什麼這很難形象化」。又一個DSL爲什麼沒有多大幫助的例子。 Python易於可視化。堅持簡單。 –

+0

我確信你對DSL的看法很低,我真的希望你永遠不會覺得自己需要一個。只要說我想把我的自行車棚塗成藍色就行了,我現在就去塗料店了。 –