1

我需要编写一个程序,将四个值的列表(可以是 I 或 O)解码为[Either Bool Bool]. 我知道我必须使用也许,但我根本无法绕过它。现在我完全绝望了,因为我根本无法解决这个问题。

示例输入和输出可能如下所示: [I,O,O,I] => [Left True, Right False]

这是我拥有的当前代码:

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.

现在任何可以帮助我解决这个问题的东西都是受欢迎的。我已经尝试了这一天的大部分时间,但我根本无法解决它。

4

1 回答 1

5

您需要在语句Just之前放置 a 以将这些值转换为,而不仅仅是:caseMaybe [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]as++仅适用于列表。这是Maybemonad 派上用场的地方:

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 语句实际上只是编写 case/nested-if 的另一种方式。我还使用模式匹配来避免使用head, !!, 并且tail因为通常应该避免使用这些函数(它们调用error而不是使用 进行正确的错误处理Maybe)。如果返回, for的<-语法Maybe将提前退出计算,所以和 say 一样。然后,不用在 case/ifs 的每个分支中构建整个结果,只需从and计算单个结果,然后在最后构建结果列表。Nothingend <- decode restif isNothing (decode rest) then Nothing else <continue>xy

于 2015-04-27T19:02:38.810 回答