Recursion 如何在F#递归算法中正确返回生成的序列

Recursion 如何在F#递归算法中正确返回生成的序列,recursion,f#,functional-programming,path-finding,chess,Recursion,F#,Functional Programming,Path Finding,Chess,作为一个指导练习,我在CS中实现了骑士之旅算法,并且工作得很好,在尝试将其移植到F#之后,我无法通过聚集骑士路径的结果序列的部分返回调用方 代码如下: let offsets = [|(-2,-1);(-2,1);(-1,-2);(-1,2);(1,-2);(1,2);(2,-1);(2,1)|]; let squareToPair sqr = (sqr % 8, sqr / 8) let pairToSquare (col, row) = row * 8 + col

作为一个指导练习,我在CS中实现了骑士之旅算法,并且工作得很好,在尝试将其移植到F#之后,我无法通过聚集骑士路径的结果序列的部分返回调用方

代码如下:

let offsets = [|(-2,-1);(-2,1);(-1,-2);(-1,2);(1,-2);(1,2);(2,-1);(2,1)|];

let squareToPair sqr = 
    (sqr % 8, sqr / 8)

let pairToSquare (col, row) = 
    row * 8 + col

// Memoizing function taken from Don Syme (http://blogs.msdn.com/b/dsyme/archive/2007/05/31/a-sample-of-the-memoization-pattern-in-f.aspx)
let memoize f =
    let cache = ref Map.empty
    fun x ->
        match (!cache).TryFind(x) with
        | Some res -> res
        | None ->
             let res = f x
             cache := (!cache).Add(x,res)
             res

let getNextMoves square = 
    let (col, row) = squareToPair square
    offsets 
    |> Seq.map    (fun (colOff, rowOff) -> (col + colOff, row + rowOff))
    |> Seq.filter (fun (c, r) -> c >= 0 && c < 8 && r >= 0 && r < 8) // make sure we don't include squares out of the board
    |> Seq.map    (fun (c, r) -> pairToSquare (c, r))

let getNextMovesMemoized = memoize getNextMoves

let squareToBoard square = 
    1L <<< square

let squareToBoardMemoized = memoize squareToBoard

let getValidMoves square board =
    getNextMovesMemoized square 
    |> Seq.filter (fun sqr -> ((squareToBoardMemoized sqr) &&& board) = 0L)

// gets all valid moves from a particular square and board state sorted by moves which have less next possible moves
let getValidMovesSorted square board =
    getValidMoves square board
    |> Seq.sortBy (fun sqr -> (getValidMoves sqr board) |> Seq.length ) 

let nextMoves = getValidMovesSorted
let sqrToBoard = squareToBoardMemoized

let findPath square = 
    let board = sqrToBoard square
    let rec findPathRec brd sqr sequence = seq {
        match brd with 
            | -1L -> yield sequence
            |   _ -> for m in nextMoves sqr do yield! findPathRec (brd ||| (sqrToBoard m)) m m::sequence
    }

    findPathRec board square [square]

let solution = findPath ((4,4) |> pairToSquare) |> Seq.take 1
let offset=[|(-2,-1);(-2,1);(-1,-2);(-1,2);(1,-2);(1,2);(2,-1);(2,1);];
设squartopair sqr=
(sqr%8,sqr/8)
让pairToSquare(col,row)=
行*8+列
//来自Don Syme的记忆功能(http://blogs.msdn.com/b/dsyme/archive/2007/05/31/a-sample-of-the-memoization-pattern-in-f.aspx)
让我们回忆一下f=
让cache=ref Map.empty
乐趣x->
将(!cache).TryFind(x)与匹配
|一些res->res
|无->
设res=fx
缓存:=(!cache).Add(x,res)
物件
让getNextMoves平方=
let(列,行)=squartopair square
抵消
|>Seq.map(乐趣(科洛夫,罗夫)->(科洛夫,罗夫,罗夫))
|>Seq.filter(fun(c,r)->c>=0&&c<8&&r>=0&&r<8)//确保我们没有将方块包括在板外
|>顺序图(乐趣(c,r)->巴黎广场(c,r))
让GetNextMovesMovied=记忆getNextMoves
设正方形到板正方形=
1L((方形板简化sqr)和面板)=0L)
//获取来自特定方块和棋盘状态的所有有效移动,按下一步可能移动次数较少的移动排序
让GetValidMovesserted方形板=
getValidMoves方形板
|>序号排序(趣味sqr->(getValidMoves sqr板)|>序号长度)
让nextMoves=getvalidmovesserted
让sqrToBoard=squartoboardemotized
让findPath平方=
let board=方形板
让rec findPathRec brd sqr sequence=seq{
匹配brd
|-1L->产量序列
|下一步移动sqr中的m的->do yield!findPathRec(brd | | | | |(sqrToBoard m))m::sequence
}
findPathRec董事会广场[广场]
让解=findPath((4,4)|>pairToSquare)|>Seq.take 1
我得到以下错误:

The type '(int64 -> seq<int>)' is not a type whose values can be enumerated with this syntax, i.e. is not compatible with either seq<_>, IEnumerable<_> or IEnumerable and does not have a GetEnumerator method (using external F# compiler)
type'(int64->seq)不是一种可以用这种语法枚举其值的类型,即与seq、IEnumerable或IEnumerable都不兼容,并且没有GetEnumerator方法(使用外部F#编译器)
我可能会误解这是如何工作的,但我希望nextMoves的结果会如下。有更好的方法吗?我错过什么了吗?有什么推荐的模式吗


提前谢谢

所以问题是
nextMoves
有类型

val nextMoves : (int -> int64 -> seq<int>)
val下一步移动:(int->int64->seq)

因为它与
getvalidmovesserted
相同。您需要提供
board
参数

nextMoves
只是
getvalidmovesserted
,它包含两个参数(
square
board
)-现在在
findPath
中,您只提供了一个参数,我猜您想写这个

nextMoves sqr board
但是,代码的其余部分还有更多的问题,很难弄清楚您想要做什么

我想你想做这样的事情:

let findPath square = 
    let board = sqrToBoard square
    let rec findPathRec brd sqr (sequence : int list) = 
        match brd with 
            | -1L -> sequence
            |   _ -> 
                [
                    for m in nextMoves sqr board do 
                    yield! findPathRec (brd ||| (sqrToBoard m)) m (m::sequence)
                ]

这将编译(但会导致堆栈溢出异常)

嗨,卡斯滕,谢谢你的回答,我怎么会错过这个呢??所以基本上我试图生成骑士访问整个棋盘一次的序列(当brd=-1L时会发生这种情况),所以我返回。否则,我必须调用递归函数来进行可能的移动。