F#:编写一个函数,以递归方式构建元组列表并更改可变变量

时间:2011-12-12 13:41:47

标签: recursion f# closures mutable

此问题与此previous thread有关。

我按照Tomas的建议使用这个代码,一切正常:

let GetSameColorNeighs (grid:Option<Ball>[,], row, col, color:Color) =
  let rec loop (row, col) = seq {
    if not (row < 0 || col < 0 || row > MaxLineNumber - 1 
                    || col > BallsPerLine - 1) then
        let ball = grid.[row,col]
        match ball with 
        | Some(ball) -> 
          if (!ball.visited = false || not <| ball.color.Equals(color)) then
            // Not sure what you want here - yield items using 'yield'?
            // [row , col] 
          else
            ball.visited := true
            yield row, col                 // Add single item to results
            yield! loop(row + 1, col + 1)  // Add all generated to results
            yield! loop(row - 1, col - 1)  //        -- || --
        | None  -> () }
  loop(row, col) |> Seq.toList

上面的代码遍历“球”的数组2d并返回具有相同颜色的相邻球的索引列表。

现在我必须修改函数,它返回一个布尔值,指示列表中至少有一个球是否满足某个条件。我以这种方式更改了代码,但似乎我无法在该代码中分配一个可变值:

let GetSameColorNeighs (grid:Option<Ball>[,], row, col, color:Color)  : List<int * int> * bool =
    let mutable b : bool = false
    let rec loop (row, col) = seq {
        if not (row < 0 || col < 0 || row > MaxLineNumber - 1 
                        || col > BallsPerLine - 1) then
            let ball = grid.[row,col]
            match ball with 
            | Some(ball) -> 
              if (ball.visited = true || not <| ball.color.Equals(color)) then
                ()
              else
                //HERE's THE PROBLEM
                if (ball_satisfy_a_certain_condition) then
                      b <- true
                ball.visited := true
                yield row, col                 // Add single item to results
                yield! loop(row + 1, col + 1)  // Add all generated to results
                yield! loop(row - 1, col - 1)  //        -- || --
            | None  -> () }
      loop(row, col) |> Seq.toList, b

似乎闭包不能获取可变变量(我不知道它的意思)。

所以我有两个问题:

  1. 为什么上面对可变变量的赋值错了?
  2. 我应该如何重构我的代码以实现这一目标?

1 个答案:

答案 0 :(得分:4)

简而言之,您必须使用ref变量而不是可变变量。

虽然可变变量在堆栈上分配,但ref变量是基于堆的。每次调用loop函数后,当ref值仍然存在时,可变值将被清除。因此,只有ref值才能在GetSameColorNeighs中返回。

这里有很多次问过这个问题。有关更深入的讨论,请参阅The mutable variable 'i' is used in an invalid way.?this blog post