2015-04-27 76 views
1

我需要編寫一個程序,解碼四個值,它可以是我還是Ø成[Either Bool Bool]名單列表。我知道我必須使用也許,但我根本無法用頭圍住它。現在我完全絕望,因爲我根本無法解決這個問題。哈斯克爾初學者無法比擬的預期類型

一個例子輸入和輸出可能是這樣的:I,O,O,I] => [左真的吧假]

下面是當前代碼我有:

module Blueprint where 
import Prelude 
import Data.Maybe 

data Bit = O | I deriving (Eq, Show) 

encode :: [Either Bool Bool] -> [Bit] 
encode [] = [] 
encode l = case head l of 
      Left False -> [I, I] ++ encode (tail l) 
      Left True -> [I, O] ++ encode (tail l) 
      Right False -> [O, I] ++ encode (tail l) 
      Right True -> [O, O] ++ encode (tail l) 

decode :: [Bit] -> Maybe [Either Bool Bool] 
decode [] = Nothing 
decode [x] = Nothing 
decode l = if isNothing (decode (tail (tail l))) 
    then Nothing 
    else case head l of 
    I -> if l!!1 == I 
      then [Left False] ++ decode (tail (tail l)) 
      else [Left True] ++ decode (tail (tail l)) 
    O -> if l!!1 == I 
      then [Right False] ++ decode (tail (tail l)) 
      else [Right True] ++ decode (tail (tail l)) 

而這些都是錯誤的,我得到:

Prelude> :load serialise 
[1 of 1] Compiling Blueprint  (serialise.hs, interpreted) 

serialise.hs:22:16: 
    Couldn't match expected type `Maybe [Either Bool Bool]' 
       with actual type `[Either Bool b0]' 
    In the expression: [Left False] ++ decode (tail (tail l)) 
    In the expression: 
     if l !! 1 == I then 
      [Left False] ++ decode (tail (tail l)) 
     else 
      [Left True] ++ decode (tail (tail l)) 
    In a case alternative: 
     I -> if l !! 1 == I then 
       [Left False] ++ decode (tail (tail l)) 
      else 
       [Left True] ++ decode (tail (tail l)) 

serialise.hs:22:33: 
    Couldn't match expected type `[Either Bool b0]' 
       with actual type `Maybe [Either Bool Bool]' 
    In the second argument of `(++)', namely `decode (tail (tail l))' 
    In the expression: [Left False] ++ decode (tail (tail l)) 

serialise.hs:23:16: 
    Couldn't match expected type `Maybe [Either Bool Bool]' 
       with actual type `[Either Bool b1]' 
    In the expression: [Left True] ++ decode (tail (tail l)) 
    In the expression: 
     if l !! 1 == I then 
      [Left False] ++ decode (tail (tail l)) 
     else 
      [Left True] ++ decode (tail (tail l)) 
    In a case alternative: 
     I -> if l !! 1 == I then 
       [Left False] ++ decode (tail (tail l)) 
      else 
       [Left True] ++ decode (tail (tail l)) 

serialise.hs:23:32: 
    Couldn't match expected type `[Either Bool b1]' 
       with actual type `Maybe [Either Bool Bool]' 
    In the second argument of `(++)', namely `decode (tail (tail l))' 
    In the expression: [Left True] ++ decode (tail (tail l)) 

serialise.hs:25:16: 
    Couldn't match expected type `Maybe [Either Bool Bool]' 
       with actual type `[Either a0 Bool]' 
    In the expression: [Right False] ++ decode (tail (tail l)) 
    In the expression: 
     if l !! 1 == I then 
      [Right False] ++ decode (tail (tail l)) 
     else 
      [Right True] ++ decode (tail (tail l)) 
    In a case alternative: 
     O -> if l !! 1 == I then 
       [Right False] ++ decode (tail (tail l)) 
      else 
       [Right True] ++ decode (tail (tail l)) 

serialise.hs:25:34: 
    Couldn't match expected type `[Either a0 Bool]' 
       with actual type `Maybe [Either Bool Bool]' 
    In the second argument of `(++)', namely `decode (tail (tail l))' 
    In the expression: [Right False] ++ decode (tail (tail l)) 

serialise.hs:26:16: 
    Couldn't match expected type `Maybe [Either Bool Bool]' 
       with actual type `[Either a1 Bool]' 
    In the expression: [Right True] ++ decode (tail (tail l)) 
    In the expression: 
     if l !! 1 == I then 
      [Right False] ++ decode (tail (tail l)) 
     else 
      [Right True] ++ decode (tail (tail l)) 
    In a case alternative: 
     O -> if l !! 1 == I then 
       [Right False] ++ decode (tail (tail l)) 
      else 
       [Right True] ++ decode (tail (tail l)) 

serialise.hs:26:32: 
    Couldn't match expected type `[Either a1 Bool]' 
       with actual type `Maybe [Either Bool Bool]' 
    In the second argument of `(++)', namely `decode (tail (tail l))' 
    In the expression: [Right True] ++ decode (tail (tail l)) 
Failed, modules loaded: none. 

眼下任何,可以幫助我解決這個問題是值得歡迎的。我已經嘗試了這一天的更好的一部分,我根本無法解決它。

回答

5

你需要把你的Just聲明case之前,這些值轉換爲Maybe [Either Bool Bool],而不是僅僅[Either Bool Bool]

decode :: [Bit] -> Maybe [Either Bool Bool] 
decode [] = Nothing 
decode [x] = Nothing 
decode l = if isNothing (decode (tail (tail l))) 
    then Nothing 
    else Just $ case head l of 
    I -> if l!!1 == I 
      then [Left False] ++ decode (tail (tail l)) 
      else [Left True] ++ decode (tail (tail l)) 
    O -> if l!!1 == I 
      then [Right False] ++ decode (tail (tail l)) 
      else [Right True] ++ decode (tail (tail l)) 

但是這不會解決所有的它。您還可以decode嵌入到計算,其類型爲Maybe [Either Bool Bool],而是利用++你只需要在[Either Bool Bool]++只列出了工作。這就是Maybe單子就派上用場了:

decode [] = Nothing 
decode [x] = Nothing 
decode (x:y:rest) = do 
    end <- decode rest 
    let this = case (x, y) of 
      (I, I) -> Left False 
      (I, O) -> Left True 
      (O, I) -> Right False 
      (O, O) -> Right True 
    return (this : end) 

這裏的case語句實在是寫你的情況/嵌套IFS的只是以不同的方式。我還使用模式匹配,以避免head!!tail所有的用途,因爲這些功能通常應避免(他們稱之爲error而不是做正確的錯誤使用Maybe處理)。該<-語法Maybe將退出計算,如果及早返回Nothing,所以end <- decode rest是相同的話說if isNothing (decode rest) then Nothing else <continue>。然後,不是在case/ifs的每個分支中構建完整的結果,只需計算從xy得到的單個結果,然後在最後構建結果列表。

+0

還要注意的是,新版本僅使用總的方法使其更安全。匹配'x/y'的模式避免了必須決定'head'還是'!! 1'以後安全。即使分析後它是安全的,避免分析也很好。 – Guvante

+0

@Ruhrpottpatriot:瞭解「可能」單子需要了解單子。在這種情況下,轉換非常簡單,您可以刪除'return' /'do'並用他提供的代碼替換'end < - decode rest',您將執行相同的執行。我一直認爲'Maybe'單子是「如果'<-'回報'Nothing'你結束了'Nothing'和'return'是'Just'的代名詞」 – Guvante

+0

@Ruhrpottpatriot了'Maybe'類型定義爲'data Maybe a = Nothing |只是一個'。沒有什麼特別的,它只有兩個構造函數:'Nothing :: Maybe a'和'Just :: a - > Maybe a'。爲了構造'Maybe a'類型的值,可以使用這兩個構造函數中的一個。對'a'類型的值應用'Just'構造一個新類型'Maybe a'的值,並且使用'Nothing'只是構造'Maybe a'類型的值,不需要輸入。 – bheklilr