2016-06-14 60 views
2

我想編譯一個語法樹到Turtle模塊的方法。lambdas樹與歧視工會的樹

module Turtle = 
    let rotateDefaultAmount amount state = ... 
    let move vector state = ... 

該選項生成代碼重複(實際上有多個命令):

type TurtleCommand = 
    | Rotate of float32 
    | Move of Vector2 
/... 
match symbol with 
     | 'w' -> Move (Vector2.up) 
     | '\' -> Rotate 90.0f 
//... 
let applyCommand command state = 
    match command with 
      | Move shift -> Turtle.move shift state 
      | Rotate amount -> Turtle.rotate amount state 
applyCommand command someState 

我這個替代它:

type TurtleCommand = TurtleState -> TurtleState 
/... 
match symbol with 
     | 'w' -> Turtle.move (Vector2.up) 
     | '\' -> Turtle.rotate 90.0f 
//... 
command someState 

現在我有一個命令Turtle.moveAndEvadeCollision。這取決於其他命令。特別是應在各move指令後執行,以確保不會進入佔用位置。另外,不應該在樹中使用move命令。

我不能寫一個方法驗證,moveAndEvadeCollision後面沒有move因爲它們都是不可區分的TurtleState -> TurtleState lambda。這是否意味着我的第一次重構是錯誤的,我應該返回重複?一個功能語言的程序是否正常,有一個由功能組成的數據結構?

回答

2

我認爲第一個版本更好,因爲它將(輸入 - >命令)和(命令 - >移動)階段分開。這對於解釋器來說是非常常見的設計,分別對應於解析和執行階段。

我不認爲有任何真正的代碼重複,儘管代碼最終會變得更長。但是你會得到一些非常實際的好處,比如能夠讓編譯器驗證你的applyState函數處理所有可能的命令。您也可以獨立測試每個部分。另外,正如您已經發現的那樣,如果您首先將輸入解析爲命令樹,則可以對整個樹進行一些靜態驗證,以確保您沒有輸入任何無效的程序。