2014-10-09 83 views
0

Rellevant類型:獲取位置

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

我有一個列表的列表,[也許INT]],我已經說

type Block = [Maybe Int] 

我是分配工作是創建一個數獨求解器,所以我需要一個函數來返回一個'空白'單元格的位置,空白爲Nothing。 數獨的實際佈局將

Sudoku [ 
     , list1 
     , list2 
     .... ] 

,直到我有九個列表,每個包含九個元素,沒有或只是詮釋。

type Pos = (Int, Int) 

第一個Int in Pos應指示哪個'行'包含空白單元格。第二個應該指出那個Row是哪個Element是空白的。 我寫

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)) 

這顯然是錯誤的,我得到錯誤類型和各種東西。它看起來很奇怪,那裏也有一個do block。任何人都可以將我指向正確的方向嗎?謝謝!

我得到這些錯誤:

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)) } 

再次編輯:此外,我敢肯定,這個功能會表現得可笑,如果沒有空白單元格..

+0

「這顯然是錯誤的,我得到錯誤類型和各種東西」。爲什麼顯然是錯的?你會得到什麼類型的錯誤? – bheklilr 2014-10-09 14:56:49

+0

更新後的錯誤! – Rewbert 2014-10-09 14:59:41

回答

3

首先,使用尾遞歸,但不是遞歸函數。

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) 

主要 - 這個代碼是無效的。 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 
+0

謝謝,寫得很好的評論!教學法,我學到了很多東西。 :) – Rewbert 2014-10-09 15:28:36

+0

...和''不是$ a'notElem' b == a'elem' b''。 – 2014-10-09 18:19:40

+0

@WillNess感謝您的確認。起初,我寫了'Nothing'elem'b',但我不確定))) – viorior 2014-10-10 07:17:48