从列表列表中获取位置

时间:2014-10-09 14:54:33

标签: haskell sudoku

相关类型:

Data Sudoku = Sudoku [[Maybe Int]]
type Block = [Maybe Int]
rows :: Sudoku -> [[Maybe Int]]
rows (Sudoku rs) = rs

我有一份清单,[[可能是国际]],我已经说过了

type Block = [Maybe Int]

我正在进行的任务是创建一个数独求解器,所以我需要一个函数来返回一个空白的位置'细胞,空白没什么。 数独的实际布局是

Sudoku [
        , list1
        , list2
        ....    ]

直到我有九个列表,每个列表包含九个元素,Nothing或Just Int。

type Pos = (Int, Int)

Pos中的第一个Int应该指出哪个' row'包含空白单元格。第二个应该指出该行中哪个元素是空白元素。 我已经写过

whichRow :: Sudoku -> Int
whichRow (Sudoku (x:xs)) =
    if isNothingPresent x == False then 1 + whichRow (Sudoku xs) else 1

whereIsNothing :: Block -> Int
whereIsNothing (x:xs) = if x == Nothing then 1 else 1 + whereIsNothing xs

isNothingPresent :: Block -> Bool
isNothingPresent b
    | Nothing `notElem` b = False
    | otherwise           = True

现在我需要组合这些函数并创建一个函数空白,它将检查数独并返回空白单元格的位置。我玩了一遍并尝试过:

blank :: Sudoku -> Pos 
blank sud = do k <- (whichRow sud)
               n <- (whereIsNothing (head (drop (k-1) (rows sud))))
               (return (k, n))

这显然是错误的,我得到了类型错误和各种各样的东西。并且在那里看起来很糟糕。有人能指出我正确的方向吗?谢谢!

我收到这些错误:

Sudoku.hs:159:22:
    Couldn't match expected type `(Int, Int)' with actual type `Int'
    In a stmt of a 'do' block: k <- (whichRow sud)
    In the expression:
      do { k <- (whichRow sud);
           n <- (whereIsNothing (head (drop (k - 1) (rows sud))));
           (return (k, n)) }

Sudoku.hs:160:22:
    Couldn't match expected type `(Int, t0)' with actual type `Int'
    In a stmt of a 'do' block:
      n <- (whereIsNothing (head (drop (k - 1) (rows sud))))
    In the expression:
      do { k <- (whichRow sud);
           n <- (whereIsNothing (head (drop (k - 1) (rows sud))));
           (return (k, n)) }

Sudoku.hs:161:24:
    Couldn't match expected type `Int' with actual type `(Int, t0)'
    Relevant bindings include n :: t0 (bound at Sudoku.hs:160:16)
    In the first argument of `return', namely `(k, n)'
    In a stmt of a 'do' block: (return (k, n))
    In the expression:
      do { k <- (whichRow sud);
           n <- (whereIsNothing (head (drop (k - 1) (rows sud))));
           (return (k, n)) }

再次编辑:另外我很确定如果没有空白单元格,这个函数会表现得很有趣。

1 个答案:

答案 0 :(得分:3)

首先,使用tail-recursive,但不使用递归函数。

whichRow :: Sudoku -> Int
whichRow s = whichRow' s 0   -- tail-recursive
  where
    whichRow' (Sudoku (x:xs)) i = if isNothingPresent x 
        then 1 
        else whichRow' (Sudoku xs) (i+1)

第二个,不要忘记在模式匹配时查看所有案例:

whichRow :: Sudoku -> Int
whichRow s = whichRow' s 0
  where
    whichRow' (Sudoku [])     i = i     -- missing case
    whichRow' (Sudoku (x:xs)) i = if isNothingPresent x 
        then 1 
        else whichRow' (Sudoku xs) (i+1)

第三,为什么要使用这么多括号?

blank :: Sudoku -> Pos 
blank sud = do k <- whichRow sud
               n <- whereIsNothing (head (drop (k-1) (rows sud)))
               return (k, n)

MAIN - 此代码无效。 do是monad,但您只使用Int。请改用let

blank :: Sudoku -> Pos 
blank sud = let k = whichRow sud in
            let n = whereIsNothing $ head $ drop (k-1) (rows sud) in
            (k, n)

where

blank :: Sudoku -> Pos 
blank sud = (k, n)
  where
    k = whichRow sud
    n = whereIsNothing $ head $ drop (k-1) (rows sud)

第四次,不要重复使用很多Bool,例如if smth == True then ....,而是写if smth then ...。我们来看看

isNothingPresent :: Block -> Bool
isNothingPresent b
    | Nothing `notElem` b = False
    | otherwise           = True

我们可以将其重写为

isNothingPresent :: Block -> Bool
isNothingPresent b = not $ Nothing `notElem` b

或者更简单地说

isNothingPresent :: Block -> Bool
isNothingPresent b = Nothing `elem` b