F#:编写一个递归构建元组列表的函数,语法错误

时间:2011-12-07 22:32:31

标签: list syntax recursion f# tuples

我正在尝试编写一个返回List<的递归函数。 int * int>,但我在语法方面遇到了一些麻烦。

当recursione结束时,函数应返回一个空列表,否则元组(int * int)与递归调用返回的List合并:

let rec foobar () : List<int * int> =
    if (recursionIsEnded) then
        []
    else 
        foobar () :: (10, 10) // this is wrong
        // (10,10) works, but I need to concatenate it with the elements returned by foobar recursive call

有人可以向我解释我做错了吗?

编辑:

我会尝试提供更多细节。 实际上我的功能有点复杂。我正在迭代2d数组并使用满足特定条件的数组索引元素构建元组列表。实际上这是我的代码:

let rec GetSameColorNeighs(grid : Option<Ball> [,], row : int , col : int, color : Microsoft.Xna.Framework.Color) : List<int * int> =
    if (row < 0 || col < 0 || row > MaxLineNumber - 1 || col > BallsPerLine - 1) then
        []
    else
        let ball = grid.[row,col]
        match ball with 
            |Some(ball) -> 

                if (!ball.visited = false || not <| ball.color.Equals(color)) then
                    [row , col]
                else
                     ball.visited := true
                     (row,col) ::GetSameColorNeighs(grid, row + 1, col + 1, color) ::  GetSameColorNeighs(grid, row - 1, col - 1, color) 

            |None  -> []

所以这里还有两个问题:):

  1. 如何修改以下行以使其编译?

    (row,col) ::GetSameColorNeighs(grid, row + 1, col + 1, color) ::  GetSameColorNeighs(grid, row - 1, col - 1, color) 
    
  2. 有没有更好的方法呢?

  3. 我不关心列表的元素顺序。

4 个答案:

答案 0 :(得分:2)

使用带累加器的内部函数可能是最简单的方法(作为奖励它的尾递归)。

let foobar() =
  let rec foobar acc =
    if (recursionIsEnded) then
        List.rev acc
    else 
        foobar ((10, 10)::acc)
  foobar []

根据您的更新,我更喜欢可变解决方案。像

这样的东西
let GetSameColorNeighs(grid : Option<Ball> [,], row : int , col : int, color : Microsoft.Xna.Framework.Color) : List<int * int> =
    let results = ResizeArray()
    let rec loop (row, col) =
      if (row < 0 || col < 0 || row > MaxLineNumber - 1 || col > BallsPerLine - 1) then ()
      else
          let ball = grid.[row,col]
          match ball with 
              |Some(ball) -> 

                  if (!ball.visited = false || not <| ball.color.Equals(color)) then
                      [row , col] //doesn't compile, not sure what to do here
                  else
                       ball.visited := true
                       results.Add(row, col)
                       loop(row + 1, col + 1) 
                       loop(row - 1, col - 1)

              |None  -> ()
    loop(row, col)
    results |> Seq.toList

答案 1 :(得分:2)

Daniel的解决方案看起来不错,但您不需要使用可变状态(ResizeArray)。相反,您可以将loop函数编写为使用yield生成结果的序列表达式,并使用yield!进行递归调用:

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

答案 2 :(得分:1)

由于foobar返回一个列表,你必须附加列表或concat然后反转

(foobar())@(10,10)但我通常会这样做

反过来说

   (10,10)::(foobar()))

然后在你回来时反转。上面有一个尾递归的问题,所以要调整你最终得到的东西:

let foobar () : List<int * int> =
  let rec inner acc =
    if (recursionIsEnded) then
        list.Rev acc
    else 
        inner ((10, 10)::acc)
  inner []
最后的反转通常会导致比将列表附加到列表

更少的操作

答案 3 :(得分:0)

虽然它是一个更简单的功能,但我希望它有助于说明这一点,因为你通过两个列表来构建元组。此函数以形式([],[])的形式输入两个列表作为输入,并将每个元素组合在一起作为新列表中的元组。

let rec pairlists twolists = 
  match twolists  with
    | ([],[]) -> []
    | (x::xs, y::ys) -> 
            (x,y)::pairlists(xs,ys)
;;

给定两个相同长度的列表(如果它们的长度不相同,则会得到错误),每次递归都会将前两个元素配对成元组(x,y)。语法:

(x,y)::pairlists(xs,ys)

真的只是在说#34;用我们当前的元素(x,y)构建一个元组,然后用剩下的列表(xs,ys)继续构建元组。

执行命令

pairlists ([1;2;3], 1;2;3])

您将获得输出:

[(1,1);(2,2);(3;3)]