【问题标题】:Complex Continuation in F#F# 中的复杂延续
【发布时间】:2011-08-22 02:52:27
【问题描述】:

我能找到的所有延续教程都是关于固定长度延续的(即数据结构在遍历时具有已知数量的项目

我正在实现 DepthFirstSearch Negamax(http://en.wikipedia.org/wiki/Negamax),当代码工作时,我想使用延续重写代码

我的代码如下

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

其中 update 使用给定移动更新游戏状态,eval 评估游戏状态并返回一个增量器(当前未使用)用于增量评估,isTerminal 评估该位置是否为结束位置。

问题是我必须注册未知数量的操作(每个剩余的 list.map 迭代)才能继续,而我实际上无法想到一种有效的方法。

由于这是一个指数算法,我显然希望尽可能保持高效(虽然我的大脑在试图解决这个问题时很痛苦,所以我想要的不仅仅是一个高效的答案)

谢谢

【问题讨论】:

    标签: f# continuations depth-first-search


    【解决方案1】:

    我认为您需要实现基于延续的List.map 版本来执行此操作。 map 的标准实现(使用 accumulator 参数)如下所示:

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

    如果您添加 continuation 作为参数并将代码转换为通过 continuation 返回,您将得到(有趣的情况是 loop 函数中的 x::xs 分支,其中我们首先使用尾调用调用f,并带有一些延续作为参数):

    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 -> ... )
    

    我不确定这是否会给您带来任何显着的性能改进。我认为如果您有非常深的递归(不适合堆栈),则主要需要延续。如果它适合堆栈,那么它可能会使用堆栈快速运行。

    另外,对显式延续样式的重写使程序有点难看。您可以通过使用计算表达式来处理延续来改进它。布赖恩有一个blog post on this very topic

    【讨论】:

      猜你喜欢
      • 2011-10-30
      • 1970-01-01
      • 1970-01-01
      • 2015-02-27
      • 2017-01-30
      • 2015-08-10
      • 1970-01-01
      • 2019-05-31
      • 1970-01-01
      相关资源
      最近更新 更多