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