F #: Написание функции, которая рекурсивно формирует список кортежей и изменяет переменную - PullRequest
4 голосов
/ 12 декабря 2011

Этот вопрос относится к этой предыдущей теме .

Я последовал совету Томаса, используя этот код, и все отлично работает:

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

Кажется, что изменяемая переменная не может быть получена замыканием (я не знаю, что это значит).

Итак, у меня есть 2 вопроса:

  1. почему вышеприведенное присвоение изменяемой переменной неверно?
  2. Как мне реорганизовать мой код для достижения этой цели?

1 Ответ

4 голосов
/ 12 декабря 2011

Короче говоря, вы должны использовать переменные ref вместо изменяемых переменных.

В то время как изменяемые переменные расположены в стеке, ref переменные основаны на куче. После каждого вызова вашей функции loop изменяемые значения стираются, когда значения ref все еще существуют. Следовательно, в GetSameColorNeighs.

допустимы только значения ref.

Этот вопрос задавался здесь много раз. См. Изменяемая переменная 'i' используется недопустимым образом .? и это сообщение в блоге для более подробного обсуждения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...