Haskell : How do I compose a recursive function that takes an element and gives gives back its list, 但有不同的数据类型?

标签 haskell types recursion

假设我有如下数据类型:

 data Cell = Cell (Maybe Player)
 data Board = Board [[Cell]]

现在我想生成一个这样的递归函数:

 genBoard :: [Cell] -> Board
 genBoard [] = []
 genBoard c = (take 3 c) : (genBoard $ drop 3 c) -- takes list of 9 Cells and gives 3x3 list of cells

显然,上述代码失败了,因为 (:) 不能将 [Cell] 添加到 Board,尽管从技术上讲,Board 只不过是 [[Cell]]。我需要将 Board 作为单独的数据类型来为其提供我自己的显示功能。

到目前为止,我想出的最好的是:

genBoardList :: [Cell] -> [[Cell]]
genBoardList [] = []
genBoardList c =  (take 3 c) : (genBoardList $ drop 3 c)

boardListToBoard :: [[Cell]] -> Board
boardListToBoard [] = Board []
boardListToBoard s = Board s

genBoard :: [Cell] -> Board
genBoard = boardListToBoard . genBoardList

但这似乎有点太长了,而且很难完成一件看似简单的事情。有什么想法可以改进我的代码吗?

最佳答案

您只需使用模式匹配从 Board 构造函数中解开列表,然后在每个步骤中将其重新包装;例如,使用 let...in:

genBoard :: [Cell] -> Board
genBoard [] = []
genBoard cs =
    let Board css = genBoard (drop 3 cs)
    in Board (take 3 cs : css)

或者,更惯用的,where 子句:

genBoard :: [Cell] -> Board
genBoard [] = []
genBoard cs = Board (take 3 cs : css)
  where
    Board css = genBoard (drop 3 cs)

另一个改进是使用模式匹配代替 takedrop:

genBoard :: [Cell] -> Board
genBoard [] = []
genBoard (c0:c1:c2:cs) = Board $ [c0, c1, c2] : css
  where
    Board css = genBoard cs

您还可以使用 split 使其更简单包装:

genBoard :: [Cell] -> Board
genBoard = Board . splitEvery 3

关于Haskell : How do I compose a recursive function that takes an element and gives gives back its list, 但有不同的数据类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9152396/

相关文章:

haskell - 为什么 Haskell 中的内存函数会消耗如此多的内存?

haskell - 概述,但在函数式编程中非常重要

Haskell 无法匹配类型,声称是刚性变量

algorithm - 递归股票最大化

c# - 您如何将其转换为迭代函数而不是使用嵌套循环递归?

haskell - 在 IO 之上构建 monad 转换器堆栈是否有正当理由?

function - Haskell IO传递给另一个功能

java - 在 Java 中将 double 转换为 String,反之亦然,而不会失去准确性

c# - 在同一方法签名中的函数的 TIn 的扩展方法中使用此类型参数的类型

javascript递归函数不停止执行