数独ソルバ

Haskell数独ソルバを書いてみた。
特徴は
・明示的な再帰は使わず (iterate ...) !! 81 を使った。(81手目に解が求まる)
・探索中のマス目状態を、未確定部分と仮確定部分に分けて持つ。

import List (partition,delete)

mark (pos@(i,j),d) cand = (cand1++) $ filter (not.null.snd) $ map del cand2 where
  (cand1,cand2) = partition p cand
  p ((k,l),_) = k /= i && l /= j && map (`div`3) [k,l] /= ij0
  ij0 = map (`div`3) [i,j]
  del (pos',ds) = (pos', if pos'==pos then [] else delete d ds)

ixs = [0..8]

solve nss = [[[n| j <- ixs, Just n <- [lookup (i,j) ds]]| i <- ixs]| (_,ds) <- ss] where
  ss = (!!81) $ iterate (>>=f) [(iniCand,[])]
  iniCand = [((i,j),ds)| i <- ixs, j <- ixs,
    let n = nss!!i!!j, let ds = if n==0 then [1..9] else [n]]
  f ([],_) = []
  f (cand,ds) = [(mark pn cand, pn:ds)|
    let (pos,ns) = snd $ minimum $ map (\x -> (length $ snd x, x)) cand,
    n <- ns, let pn = (pos,n)]

sample = [
  [8,0,0,0,3,4,0,5,0],
  [0,0,2,0,0,0,0,0,1],
  [0,1,0,9,0,0,0,0,0],
  [0,0,8,0,0,9,0,0,6],
  [5,0,0,0,1,0,0,0,8],
  [6,0,0,4,0,0,7,0,0],
  [0,0,0,0,0,1,0,7,0],
  [2,0,0,0,0,0,1,0,0],
  [0,9,0,5,6,0,0,0,2]]

として

> mapM_ ((>>putStr"\n").mapM_ print) $ solve sample
[8,6,7,1,3,4,2,5,9]
[9,5,2,6,7,8,3,4,1]
[4,1,3,9,5,2,6,8,7]
[7,4,8,3,2,9,5,1,6]
[5,3,9,7,1,6,4,2,8]
[6,2,1,4,8,5,7,9,3]
[3,8,6,2,4,1,9,7,5]
[2,7,5,8,9,3,1,6,4]
[1,9,4,5,6,7,8,3,2]

http://www.haskell.org/haskellwiki/Sudoku を見たらいろんな数独ソルバが載っていた。