Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
List F#:编写递归构建元组列表的函数是一个语法错误_List_Syntax_Recursion_F#_Tuples - Fatal编程技术网

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

List F#:编写递归构建元组列表的函数是一个语法错误,list,syntax,recursion,f#,tuples,List,Syntax,Recursion,F#,Tuples,我试图编写一个递归函数,返回一个列表,但语法有点问题 递归结束时,函数应返回空列表,否则元组(int*int)将与递归调用返回的列表合并: let rec foobar () : List<int * int> = if (recursionIsEnded) then [] else foobar () :: (10, 10) // this is wrong // (10,10) works, but I need

我试图编写一个递归函数,返回一个列表,但语法有点问题

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

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
  • 有没有更好的办法


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

    因为foobar返回一个列表,所以您必须附加列表或concat,然后反转

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

    相反

       (10,10)::(foobar()))
    
    然后当你回来的时候,把它倒过来。上面提到的尾部递归有一个问题,因此对于tweek,您最终会得到如下结果:

    let foobar () : List<int * int> =
      let rec inner acc =
        if (recursionIsEnded) then
            list.Rev acc
        else 
            inner ((10, 10)::acc)
      inner []
    
    let foobar():列表=
    让rec内部acc=
    如果(结束)那么
    列表。修订版acc
    其他的
    内部((10,10)::acc
    内部[]
    

    与使用带累加器的内部函数将列表附加到列表中相比,在最后进行反转通常会导致更少的操作,这可能是最简单的方法(另外,它的尾部递归)

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

    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
    
    让GetSameColorNeighs(网格:选项[,],行:int,列:int,颜色:Microsoft.Xna.Framework.color):列表=
    let results=ResizeArray()
    让rec循环(行、列)=
    如果(行<0 | |列<0 | |列>MaxLineNumber-1 | |列>BallsPerLine-1),则()
    其他的
    让球=网格。[行,列]
    比赛
    |一些(球)->
    
    如果(!ball.visted=false | | notDaniel的解决方案在我看来很好,但是您不需要使用可变状态(
    ResizeArray
    ),相反,您可以将
    循环
    函数编写为序列表达式,使用
    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
    
    让GetSameColorNeighs(网格:选项[,],行,列,颜色:颜色)=
    让rec循环(行,列)=序列{
    如果不是(行<0 | |列<0 | |行>MaxLineNumber-1
    ||col>BallsPerLine-1)然后
    让球=网格。[行,列]
    比赛
    |一些(球)->
    如果(!ball.visted=false | | not()}
    循环(行、列)|>顺序列表
    
    虽然它是一个更简单的函数,但我希望它能帮助您在递归两个列表以构建元组时说明这一点。此函数以([],[])的形式将两个列表作为输入,并将每个元素作为一个元组配对到一个新列表中

    let rec pairlists twolists = 
      match twolists  with
        | ([],[]) -> []
        | (x::xs, y::ys) -> 
                (x,y)::pairlists(xs,ys)
    ;;
    
    给定两个长度相同的列表(如果它们的长度不相同,则会出现错误),每个递归将前两个元素配对成一个元组(x,y)。语法:

    (x,y)::pairlists(xs,ys)
    
    实际上只是说“使用当前元素(x,y)构建一个元组,然后继续使用列表的其余部分(x,y)构建元组”

    运行:

    您将得到以下输出:

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

    我需要澄清一下。如果在else分支中,我需要连接对foobar的更多调用的结果,该怎么办使用累加器的正确语法是什么?我如何修改你的代码?foobar有一些参数吗?@Heisenbug序列表达式的另一个很好的特性,你可以从
    for
    循环(而不是使用递归进行迭代)中生成内容。但是,我不确定这在这种情况下是否有用(取决于您处理2D数组的方式)。实际上,我正在从数组的给定元素开始,构建一个具有相同颜色的绝热球列表。构建列表后,我将返回一个数组副本,该数组中没有索引的元素(因为它们是可选的)。在(!ball.visitored=false | | | not…?而不是比赛,然后如果?@Heisenbug这主要是托马斯的问题,他必须说他很有经验:)我想知道他是否有理由选择if而不是when构造。@RuneFS-不是真的,没有理由。我只是从Daniel那里获取了原始代码,只做了最小的更改。在
    when
    中指定条件对我来说很好(只要条件不太复杂,不难阅读)。
    let rec pairlists twolists = 
      match twolists  with
        | ([],[]) -> []
        | (x::xs, y::ys) -> 
                (x,y)::pairlists(xs,ys)
    ;;
    
    (x,y)::pairlists(xs,ys)
    
    pairlists ([1;2;3], 1;2;3])
    
    [(1,1);(2,2);(3;3)]