Using only list comprehensions:
type Matrix a = [[a]]
type Grid = Matrix Int
choicesComp :: Grid -> Matrix [Int]
choicesComp rows =
[[[d | d <- [1..9], n == 0 || d == n] | n <- row] | row <- rows]The input contract restricts each cell to zero or a digit from one to nine. A definition using standard list functions is:
choicesMap :: Grid -> Matrix [Int]
choicesMap = map (map choice)
where
choice :: Int -> [Int]
choice 0 = [1..9]
choice n = [n]
choices :: Grid -> Matrix [Int]
choices = choicesMapBoth preserve the row structure and construct the initial constraint domains of the Sudoku problem. The alternative names let both definitions coexist; either can supply
choices.The recursive Cartesian product is:
cpRec :: [[a]] -> [[a]]
cpRec [] = [[]]
cpRec (xs:xss) = [x:ys | x <- xs, ys <- cpRec xss]The corresponding right fold is:
cpFold :: [[a]] -> [[a]]
cpFold = foldr step [[]]
where
step :: [a] -> [[a]] -> [[a]]
step xs acc = [x:ys | x <- xs, ys <- acc]
cp :: [[a]] -> [[a]]
cp = cpRecThe base
[[]] is essential: there is one way to choose from no factors, namely the empty selection. For a nonempty outer list, choose its first coordinate and prepend it to each selection from the remaining factors. This also proves equality with the right fold by structural induction. An empty factor produces no selections.expand :: Matrix [a] -> [Matrix a]
expand = cp . map cpThe inner Cartesian product converts one row of cell choices into its possible rows; the outer product combines those rows into whole matrices. Every assignment is represented exactly once when each cell's alternatives are distinct. Empty cell domains yield no grids, and an empty matrix yields the singleton list containing the empty matrix.
Enumerate assignments and retain exactly the valid completions:
solve :: Grid -> [Grid]
solve = filter complete . expand . choicesWith blank cells and all other entries fixed, the unpruned Cartesian product has candidate grids. Testing
complete enforces every row, column and box condition. This is the size of the full candidate search; lazy evaluation can stop earlier if the caller demands only an initial portion of the solution list.Prune until a fixed point before enumerating the surviving domains:
stable :: Eq a => (a -> a) -> a -> a
stable f x = let y = f x
in if y == x then x else stable f y
solve :: Grid -> [Grid]
solve = filter complete . expand . stable prune . choicesNew singleton cells can make a later pruning pass effective even if one pass has already run. Under the supplied deletion-only, solution-preserving contract, fixed-point pruning of finite constraint domains terminates: every changed pass strictly decreases the total number of candidates, initially at most . No valid solution is removed. An empty domain causes
expand to return no candidates; a fixed point with unresolved alternatives still needs enumeration and the final complete test. Articles by others on the same topic
There are currently no matching articles.