【问题标题】:How can I correctly return produced sequences in an F# recursive algorithm如何在 F# 递归算法中正确返回生成的序列
【发布时间】:2023-03-18 22:31:01
【问题描述】:

作为一个辅导练习,我在 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<_>。有没有更好的方法来做到这一点?我错过了什么吗?有什么推荐的模式吗?

提前致谢!

【问题讨论】:

    标签: functional-programming f# path-finding chess knights-tour


    【解决方案1】:

    所以问题是nextMoves 有类型

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

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

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

      • 嗨,Carsten,感谢您的回答,我怎么错过了?所以基本上我正在尝试生成骑士访问整个棋盘一次的序列(当 brd = -1L 时发生这种情况)所以我返回。否则我必须调用递归函数来进行可能的移动。
      猜你喜欢
      • 1970-01-01
      • 2015-01-21
      • 1970-01-01
      • 2016-05-18
      • 1970-01-01
      • 2021-09-26
      • 1970-01-01
      • 1970-01-01
      • 2014-11-29
      相关资源
      最近更新 更多