我试图编写一些Haskell代码,这些代码会吐出一堆有效的数独游戏。继承了我到目前为止的代码:
import Data.List (nub, permutations, transpose)
-- Recursively build list of possible permutations of a certain length, allowing duplicates
genPermutations list length
| length <= 0 = [[]]
| length == 1 = [[a] | a <- list]
| otherwise = [[a]++b | a <- list, b <- genPermutations list $ length - 1]
-- Generate as flat list of length 9, then format
squares = [[take 3 a,take 3 $ drop 3 a, drop 6 a] | a <- permutations [1..9]]
sudokus = [[take 3 a,take 3 $ drop 3 a, drop 6 a] | a <- genPermutations squares 9]
-- Takes a sudoku as a 4d array, return True/Flase based on rules of sudoku
-- Does not check for duplicates within a square because generated sudokus shouldn't have any
checkSudukoValid x = (foldr (==) True $ map screenLineForDuplicates x) && (foldr (==) True $ map screenLineForDuplicates $ transposeSudoku x)
where transposeSudoku x = transpose(map (\x -> map transpose x ) x)
screenLineForDuplicates [[],[],[]] = True
screenLineForDuplicates [a:al,b:bl,c:cl] = check && screenLineForDuplicates [al,bl,cl]
where check = (length line) == (length $ nub line)
line = concat [a,b,c]
-- Known good sudoku for testing
knownGood = [[[[9,8,3],[6,1,4],[5,2,7]],[[6,5,7],[2,8,9],[4,3,1]],[[2,4,1],[5,7,3],[9,6,8]]],[[[8,6,5],[4,3,1],[7,9,2]],[[3,2,4],[7,9,8],[1,6,5]],[[7,1,9],[6,5,2],[3,8,4]]],[[[2,7,8],[3,5,9],[1,4,6]],[[5,1,3],[8,4,6],[9,7,2]],[[4,9,6],[1,2,7],[8,3,5]]]]
此代码的重要部分是它生成一个可能有效的数独谜题列表&amp;一个方法,如果一个谜题是有效的。根据我的理解,我应该能够过滤所述列表以获得一些有效的sudokus:
head $ filter checkSudukoValid sudokus
当我运行时,GHCI杀死我的进程,这似乎是因为内存问题。我不明白的是为什么我遇到了记忆问题。难道不能懒得过滤掉列表中的项目吗?为什么这会占用比filter checkSudukoValid $ take 5 sudokus
关于Haskell如何处理导致此问题的无限列表,我错过了什么?有没有一个标准的解决方案让这个更懒惰会导致我不会遇到内存问题?
答案 0 :(得分:2)
问题肯定在生成代码中,而不是检查代码(尽管有很多事情都应该在两者中进行更改)。具体来说,您的genPermutations
实现似乎使用越来越多的RAM。我还没弄清楚为什么会这样,但如果你使用
genPermutations xs n = map (take n) $ permutations xs
内存使用率下降到常数。但是,这实际上不会使您的程序正常工作,至少有两个原因。
一个原因是你的有效性测试是错误的;正如我之前提到的,折叠(==)
并不符合您的想法。你的意思是
checkSudukoValid x = (all screenLineForDuplicates x) && (all
screenLineForDuplicates $ transposeSudoku x)
where transposeSudoku x = transpose(map (\x -> map transpose x ) x)
screenLineForDuplicates [[],[],[]] = True
screenLineForDuplicates [a:al,b:bl,c:cl] = check && screenLineForDuplicates [al,bl,cl]
where check = (length line) == (length $ nub line)
line = concat [a,b,c]
这非常低效,但我认为这可能是正确的。
另一个原因更严重:使用我的版本genPermutations
或你的版本,你会在获得第一个有效版本之前得到大量无效的谜题。我没耐心等待它。
答案 1 :(得分:0)
尝试使用:
genPermutations list length = sequence (replicate length list)