【发布时间】:2015-03-10 12:04:02
【问题描述】:
我正在尝试编写一些 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]]]]
此代码的重要部分是它生成一个可能有效的数独谜题列表以及一个方法,如果单个谜题是有效的。根据我的理解,我应该能够过滤所述列表以获得一些有效的数独:
head $ filter checkSudukoValid sudokus
当我运行它时,GHCI 会终止我的进程,这似乎是因为内存问题。我不明白为什么我会遇到内存问题。 haskell 不应该一次懒惰地过滤列表中的项目吗?为什么这会比 filter checkSudukoValid $ take 5 sudokus 占用更多的内存
关于 Haskell 如何处理会导致这种情况的无限列表,我缺少什么?是否有一个标准的解决方案可以让这个更懒惰,让我不会遇到内存问题?
【问题讨论】:
-
你能告诉我们你收到的错误吗?
-
可能是
checkSudokuValid需要很长时间。对head $ filter checkSudokusValid $ take n sudokus进行一些实验,在其中增加n,直到找到内存不足的位置。看看你是否可以在sudokus中找到导致checkSudokusValid内存不足的元素。 -
我怀疑这与它有很大关系,但是
foldr (==) True是一个非常奇怪的写法。也许你的意思是and,也就是foldr (&&) True,或者你的意思是(\xs -> and $ zipWith (==) xs (tail xs))。 -
@MrGlass,不,折叠
(==)不会做你认为它会做的事情。例如foldr (==) True [a,b] = a == (b == True) = (a && b) || (not a && not b) = a == b,然后是foldr (==) True [a,b,c] = a == (b == c) = (a && b==c) || (not a && b/=c),你已经有了一些非常奇怪的东西。尝试对foldr (==) True的实际作用提出一个简单的解释实际上可能会相当有趣,但它肯定不是你在野外可能看到的。 -
@dfeuer
(False ==)是not和(True ==)是id。所以foldr (==) True告诉参数列表中Falses 是偶数还是奇数。