将函数名称更改为list,haskell时出错

时间:2017-01-06 19:21:50

标签: haskell

我差不多完成了我的代码,但我必须做一些修改。这是我的代码:

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.

1 个答案:

答案 0 :(得分:1)

第一个错误告诉您新的blanks定义错误。原因是应用于head的{​​{1}}会返回[Pos],这与您要返回的类型不同。

您在两种情况下使用Pos

  1. 在模式绑定中:blanks(第二个错误)
  2. (x, y) = blanks的第二个参数中,即update(第三个错误)
  3. (blanks x)函数的这两个用法要求它返回单个blanks

    我建议:

    1. 不要更改功能类型,而是将Pos重命名为blanks或更有意义的内容
    2. 完全删除firstBlank并将其出现位置替换为blanks