3

作为一个辅导练习,我在 CS 中实现了 Knights Tour 算法并且工作正常,在尝试将其移植到 F# 之后,我无法超越我聚合 Knight 路径的结果序列以返回给调用者的部分。

代码是这样的:

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

我收到以下错误:

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)

我可能会误解这是如何工作的,但我希望 nextMoves 的结果是 seq<_>。有没有更好的方法来做到这一点?我错过了什么吗?有什么推荐的款式吗?

提前致谢!

4

2 回答 2

1

所以问题是nextMoves有类型

val nextMoves : (int -> int64 -> seq<int>)

因为它与 相同getValidMovesSorted。您需要提供board论据

于 2015-09-25T04:18:15.633 回答
1

nextMoves只是getValidMovesSorted它需要两个参数(squareboard) - 现在 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)
                ]

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

于 2015-09-25T04:19:54.987 回答