2010-11-29 23 views
1

嗨看看this线程已经在处理这个问题 而且this线程可能是intrest。需要帮助写一个函数在Haskell中的应用程序

我试着写一个函数

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]

+3

这功课吗? – Paul 2010-11-29 20:01:55

回答

5

我记得在大学里做我的算法类项目。我最好的建议,特别是对于在哈斯克尔学习而不是为了生产而写作的人,应该写下'自上而下'。首先,问问你自己,你需要做些什么来解决这个问题?然后用描述性函数写下来(即使它们还不存在)。然后存根你需要的功能。例如,一开始可能是:

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的类型是什么,它为什么键入检查?它不是一个特殊的关键字;它仅仅是一个预定义的功能。

+0

+1为自上而下的方法。我必须亲自尝试。 – spade78 2010-12-13 04:59:25

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