需要帮助在Haskell中编写函数候选者

时间:2010-11-29 19:59:18

标签: haskell ghci

嗨,看看已经处理过这个主题的this线程 而this线程也可能是有趣的。

我正在尝试编写一个函数

candidates :: Sudoku -> Pos -> [Int]

给予数独

data Sudoku = Sudoku { rows :: [[Maybe Int]] }
 deriving ( Show, Eq )

和一个职位(type Pos = (Int, Int)) 确定您可以在那里写入的数字,例如在已包含(1,2,4,7,9,x,x)的数独行中,您无法写入最后一行中任何已存在的数字。另一个问题是检查高度和宽度,因此没有数字出现多次(普通的数独规则)。那么关于如何开始的任何建议?

实施例:   独>候选人示例(0,2) [4,8]

2 个答案:

答案 0 :(得分:5)

我记得在大学的算法课上做这个项目。我最好的建议,特别是那些在Haskell写作学习而非制作的人,就是写“自上而下”。首先,问问自己,你需要做些什么来解决这个问题?然后用描述性函数将其写下来(即使它们尚不存在)。然后存根你需要的功能。例如,一个开头可能是:

candidates :: Sudoku -> Pos -> [Int]
candidates s p = union (rowCands s p) (colCands s p) (blockCands s p)

rowCands :: Sudoku -> Pos -> [Int]
rowCands = undefined
colCands :: Sudoku -> Pos -> [Int]
colCands = undefined
blockCands :: Sudoku -> Pos -> [Int]
blockCands = undefined

从此开始,您只需开始描述如何解决rowCands问题,直到您回答完所有问题为止。请注意,有时您会想要编写类似于union的函数,但肯定已经编写过了。尝试查看http://haskell.org/hoogle。您可以搜索功能名称甚至键入签名。也许在标准库中已经有了union某处?

作为一个有趣的问题,您可以自己回答,undefined的类型是什么?为什么要键入检查?它不是一个特殊的关键字;它只是一个预定义的功能。

答案 1 :(得分:0)

以下是使用Data.Set的解决方案。您可以使用S.elems获取列表,但如果您正在制作数独求解器,那么您可能正在寻找S.size

import qualified Data.Set as S
import Data.Maybe(catMaybes)   

fullSet = S.fromAscList [1..9]

fromJustL = S.fromList . concatMaybes

candidates s x =
  rowSet s x `S.intersection` colSet s x `S.intersection` cellSet s x

rowSet s (i,_) = fullSet `S.difference` fromJustL (s !! i)
colSet s (_,i) = fullSet `S.difference` fromJustL (map (!!i) s)
cellSet s (i,j) = fullSet `S.difference` fromJustL (concatMap (g j) (g i s))
  where
  g i | i < 3     = take 3 
      | i < 6     = take 3 . drop 3
      | otherwise = take 3 . drop 6