2011-05-10 56 views
7

所有延續教程我能看到的是在固定長度的延長體(即數據結構具有已知的一些項目,因爲它正在走過情結延續

我實現深度優先搜索Negamax(HTTP:// EN .wikipedia.org /維基/ Negamax),並在代碼的工作,我想使用continuation

重寫代碼

我的代碼如下所示

let naiveDFS driver depth game side = 
    List.map (fun x -> 
     //- negamax depth-1 childnode opposite side 
     (x, -(snd (driver (depth-1) (update game x) -side)))) 
           (game.AvailableMoves.Force()) 
    |> List.maxBy snd 



let onPlay game = match game.Turn with 
        | Black -> -1 
        | White -> 1 

///naive depth first search using depth limiter 
let DepthFirstSearch (depth:int) (eval:Evaluator<_>) (game:GameState) : (Move * Score) = 
    let myTurn = onPlay game 

    let rec searcher depth game side = 
     match depth with 
     //terminal Node 
     | x when x = 0 || (isTerminal game) -> let movescore = (eval ((),game)) |> fst 
               (((-1,-1),(-1,-1)),(movescore * side)) 
     //the max of the child moves, each child move gets mapped to 
     //it's associated score 
     | _ -> naiveDFS searcher depth game side 

其中更新來更新遊戲狀態有帶一個給定的移動,eval評估遊戲狀態和r會產生一個增量值(當前未使用)用於增量評估,isTerminal會評估該位置是否爲結束位置。

問題是我必須註冊未知數量的動作(每個剩餘的list.map迭代)才能繼續,而實際上我無法想象這樣做的有效方式。

因爲這是一個指數算法,我顯然希望保持這種儘可能高效(雖然我的大腦好痛試圖弄清楚這是我們的,所以我想要的答案不是一個有效率的多)

謝謝

回答

5

我認爲您需要實施List.map的延續版本來執行此操作。 的標準實現的map(使用蓄能器參數)看起來是這樣的:

let map' f l = 
    let rec loop acc l = 
    match l with 
    | [] -> acc |> List.rev 
    | x::xs -> loop ((f x)::acc) xs 
    loop [] l 

如果添加延續作爲參數和改造碼通過繼續回來,你會得到(有趣情況是在loop功能,在這裏我們首先使用尾部調用一些延續作爲參數)調用fx::xs分支:

let contMap f l cont = 
    let rec loop acc l cont = 
    match l with 
    | [] -> cont acc |> List.rev 
    | x::xs -> f x (fun x' -> loop (x'::acc) xs cont) 
    loop [] l cont 

然後你就可以把正常List.map轉化爲這樣的延續版本:

// Original version 
let r = List.map (fun x -> x*2) [ 1 .. 3 ] 

// Continuation-based version 
contMap (fun x c -> c(x*2)) [ 1 .. 3 ] (fun r -> ...) 

我不確定這是否會給您帶來任何顯着的性能提升。如果你有很深的遞歸(不適合堆棧),我認爲主要需要延續。如果它適合堆棧,那麼它可能會使用堆棧快速運行。

此外,重寫爲明確的延續風格使得程序有點難看。通過使用計算表達式來處理延續,可以改善這一點。 Brian有一個blog post on this very topic