我差不多完成了我的代码,但我必须做一些修改。这是我的代码:
module Sudoku where
import Data.Char
import Data.List
import Data.Maybe
import Test.QuickCheck
data Sudoku = Sudoku { rows :: [[Maybe Int]] }
deriving (Show, Eq)
example :: Sudoku
example = Sudoku [[Just 3, Just 6, Nothing,Nothing,Just 7, Just 1, Just 2, Nothing,Nothing]
, [Nothing,Just 5, Nothing,Nothing,Nothing,Nothing,Just 1, Just 8, Nothing]
, [Nothing,Nothing,Just 9, Just 2, Nothing,Just 4, Just 7, Nothing,Nothing]
, [Nothing,Nothing,Nothing,Nothing,Just 1, Just 3, Nothing,Just 2, Just 8]
, [Just 4, Nothing,Nothing,Just 5, Nothing,Just 2, Nothing,Nothing,Just 9]
, [Just 2, Just 7, Nothing,Just 4, Just 6, Nothing,Nothing,Nothing,Nothing]
, [Nothing,Nothing,Just 5, Just 3, Nothing,Just 8, Just 9, Nothing,Nothing]
, [Nothing,Just 8, Just 3, Nothing,Nothing,Nothing,Nothing,Just 6, Nothing]
, [Nothing,Nothing,Just 7, Just 6, Just 9, Nothing,Nothing,Just 4, Just 3]
]
-- A
-- Crates a blank sudoku "map"
allBlankSudoku :: Sudoku
allBlankSudoku = Sudoku (replicate 9 (replicate 9 Nothing))
-- Checks if the criterias meet the standard sudoku
isSudoku :: Sudoku -> Bool
isSudoku x = (length (rows x) == 9) && ( and [length y == 9 | y <- rows x]) && ( and [x > 0 && x < 10 | Just x <- concat (rows x)])
-- Checks if the sudoku puzzle is solved. Which is when there is no more cells to fill in
isSolved :: Sudoku -> Bool
isSolved x = Nothing `notElem` concat (rows x)
-- Prints a sudoko
printSudoku :: Sudoku -> IO()
printSudoku x = putStr (unlines ([ map convertInt y | y <- rows x]))
-- converting from int to char
convertInt :: Maybe Int -> Char
convertInt Nothing = '.'
convertInt (Just x) = chr (x+48)
-- simply reads sudoku from file
readSudoku :: FilePath -> IO Sudoku
readSudoku x =
do y <- readFile x
return (Sudoku [map convertChar c | c <- lines y])
-- Convertion from char to int.
convertChar :: Char -> Maybe Int
convertChar '.' = Nothing
convertChar x = Just (digitToInt x)
-- this function crates a cell
cell :: Gen (Maybe Int)
cell = frequency
[(1, do n <- choose (1,9)
return (Just n)),
(9, return Nothing)]
-- C2. Make Sudokus an instance of the class Arbitrary.
instance Arbitrary Sudoku where
arbitrary =
do rows <- sequence [ sequence [ cell | j <- [1..9] ] | i <- [1..9] ]
return (Sudoku rows)
-- check sudoku
prop_Sudoku :: Sudoku -> Bool
prop_Sudoku x = isSudoku x
type Block = [ Maybe Int]
-- CHeck if block containts same digit twice
isOkayBlock :: Block -> Bool
isOkayBlock x = x' == nub x'
where x' = filter isJust x
-- create list of all blocks
blocks :: Sudoku -> [Block]
blocks x = rows x ++ transpose (rows x) ++ blocks1 x
-- 3x3 made by blocks
blocks1 :: Sudoku -> [Block]
blocks1 x = [concat [take 3 (drop a b) | b <- take 3 (drop d (rows x))] | a <- [0,3,6] , d <- [0,3,6]]
-- checks the whole sudoku
isOkay :: Sudoku -> Bool
isOkay x = and (map isOkayBlock (blocks x))
prop_isOkay x = and [ length a == 9 | a <- blocks x ] && length (blocks x) == 27
type Pos = (Int,Int)
blanks :: Sudoku -> Pos
blanks = head . allBlanks
-- Changed the way blanks works,
(!!!) :: [[a]] -> Pos -> a
(!!!) l (y,x) = (l !! y) !! x
-- Get the blanks in sudoku.
allBlanks :: Sudoku -> [Pos]
allBlanks s = [ (y,x) | y <- [0..8], x <- [0..8], ((rows s) !!! (y,x)) == Nothing]
prop_isBlank :: Sudoku -> Bool
prop_isBlank sud = (selElement (selectRow (rows sud) x) y) == Nothing
where (x, y) = blanks sud
selectRow :: [[a]] -> Int -> [a]
selectRow (x:_) 0 = x
selectRow (x:xs) n = selectRow xs (n-1)
selElement :: [a] -> Int -> a
selElement (x:_) 0 = x
selElement (x:xs) n = selElement xs (n-1)
--Replace/update
(!!=) :: [a] -> (Int ,a) -> [a]
(x:xs) !!= (0,a) = (a:xs)
(x:xs) !!= (y,a) = (x:(xs!!=(y-1,a)))
prop_replacedElement :: [Int] -> (Int,Int) -> Property
prop_replacedElement list (index, obj) = list /= [] ==> (list !!= (index', obj)) !! index' == obj
where
index' = index `mod` length list
-- Update cell with new value
update :: Sudoku -> Pos -> Maybe Int -> Sudoku
update x (p,i) y = Sudoku ((rows x) !!= (p,z))
where z = (rows x) !! p !!= (i,y)
-- Check update function
prop_update (x,y) sud n = prop_XY (x',y') (update sud (x',y') n) == n
where x' = x `mod` 9
y' = y `mod` 9
-- helepr to find specific value
prop_XY (x,y) sud = ((!!) (rows (sud)) x) !! y
-- Gives allowed numbers on an empty cell
candidates :: Sudoku -> Pos -> [Int]
candidates sud (x,y) = filter (/=0) [if isOkay (update sud (x,y) (Just z)) == True then z else 0 | z <- [1..9]]
solve :: Sudoku -> Maybe Sudoku
solve x
| not(isOkay x) = Nothing
| isSolved x = Just x
| otherwise = solve' [solve $ update x (blanks x) (Just c) | c <- [1..9]]
-- take from our list solutions
solve' :: [Maybe a] -> Maybe a
solve' [] = Nothing
solve' (Nothing:xs) = solve' xs
solve' (Just x:xs) = Just x
-- read and solves the sudoku.
readAndSolve :: FilePath -> IO ()
readAndSolve x = do
y <- readSudoku x
case solve y of
Nothing -> putStrLn"(no solution)"
Just y -> printSudoku y
-- check if x 2 solution to x1
isSolutionOf :: Sudoku -> Sudoku -> Bool
isSolutionOf x1 x2 = isOkay x1 && isSolved x1 && isSolutionOf2 (zip (concat(rows x1)) (concat(rows x2)))
-- helper func
isSolutionOf2 :: (Eq a) => [(Maybe a, Maybe a)] -> Bool
isSolutionOf2 [] = True
isSolutionOf2 ((x,y):xs) = x == y || y == Nothing && isSolutionOf2 xs
-- Solved or not
prop_SolveSound :: Sudoku -> Property
prop_SolveSound x = isOkay x ==> (fromJust (solve x)) `isSolutionOf` x
现在我必须改变功能:
blanks :: Sudoku -> Pos
为:
blanks :: Sudoku -> [Pos]
但是当我这样做时,我会得到一些错误,我不知道如何修复。我试图改变,以便在我的解释定义中使用函数“head”。代码示例表示赞赏。
修改
忘记了错误:
Sudoku.hs:99:10: error:
• Couldn't match type ‘(Int, Int)’ with ‘[Pos]’
Expected type: Sudoku -> [Pos]
Actual type: Sudoku -> Pos
• In the expression: head . allBlanks
In an equation for ‘blanks’: blanks = head . allBlanks
Sudoku.hs:111:19: error:
• Couldn't match expected type ‘(t, t1)’ with actual type ‘[Pos]’
• In the expression: blanks sud
In a pattern binding: (x, y) = blanks sud
In an equation for ‘prop_isBlank’:
prop_isBlank sud
= (selElement (selectRow (rows sud) x) y) == Nothing
where
(x, y) = blanks sud
• Relevant bindings include
x :: t (bound at Sudoku.hs:111:11)
y :: t1 (bound at Sudoku.hs:111:14)
Sudoku.hs:155:48: error:
• Couldn't match type ‘[Pos]’ with ‘(Int, Int)’
Expected type: Pos
Actual type: [Pos]
• In the second argument of ‘update’, namely ‘(blanks x)’
In the second argument of ‘($)’, namely
‘update x (blanks x) (Just c)’
In the expression: solve $ update x (blanks x) (Just c)
Failed, modules loaded: none.
答案 0 :(得分:1)
第一个错误告诉您新的blanks
定义错误。原因是应用于head
的{{1}}会返回[Pos]
,这与您要返回的类型不同。
您在两种情况下使用Pos
:
blanks
(第二个错误)(x, y) = blanks
的第二个参数中,即update
(第三个错误) (blanks x)
函数的这两个用法要求它返回单个blanks
。
我建议:
Pos
重命名为blanks
或更有意义的内容firstBlank
并将其出现位置替换为blanks