实际类型是`Maybe (Maybe [(Nucleotide, Int)])`,而我希望它是`[(Nucleotide, Int)]`

Ada*_*ner 0 haskell

我目前正在学习 Haskell,并且正在https://exercism.io/上研究核苷酸计数问题。问题:

给定一个代表 DNA 序列的字符串,计算每个核苷酸的数量。如果字符串包含非 A、C、G 或 T 的字符,则它是无效的,您应该发出错误信号。

编译器给了我以下错误:

/Users/adamzerner/Exercism/haskell/nucleotide-count/src/DNA.hs:8:88: error:
    • Couldn't match expected type ‘[(Nucleotide, Int)]’
                  with actual type ‘Maybe (Maybe [(Nucleotide, Int)])’
    • In the first argument of ‘Map.fromList’, namely ‘(Just result)’
      In the first argument of ‘Right’, namely
        ‘(Map.fromList (Just result))’
      In the expression: Right (Map.fromList (Just result))
  |
8 | nucleotideCounts xs = if result == Nothing then Left "Error" else Right (Map.fromList (Just result))
  |                                                                                        ^^^^^^^^^^^

/Users/adamzerner/Exercism/haskell/nucleotide-count/src/DNA.hs:16:45: error:
    • Couldn't match expected type ‘[(Nucleotide, Int)]’
                  with actual type ‘Maybe (Maybe [(Nucleotide, Int)])’
    • In the second argument of ‘updateAcc'’, namely ‘(Just acc)’
      In the second argument of ‘($)’, namely ‘updateAcc' el (Just acc)’
      In the expression: Just $ updateAcc' el (Just acc)
   |
16 |   | isNucleotide el = Just $ updateAcc' el (Just acc)
   |                                             ^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

对于两者,我都希望它应该是[(Nucleotide, Int)]而不是Maybe (Maybe [(Nucleotide, Int)]). 这是我的代码:

module DNA (nucleotideCounts, Nucleotide(..)) where

import qualified Data.Map as Map

data Nucleotide = A | C | G | T deriving (Eq, Ord, Show)

nucleotideCounts :: String -> Either String (Map.Map Nucleotide Int)
nucleotideCounts xs = if result == Nothing then Left "Error" else Right (Map.fromList (Just result))
  where
    result = Prelude.foldr updateAcc (Just acc) xs
    acc = [(A, 0), (C, 0), (G, 0), (T, 0)]

updateAcc :: Char -> Maybe [(Nucleotide, Int)] -> Maybe [(Nucleotide, Int)]
updateAcc _ Nothing = Nothing
updateAcc el acc
  | isNucleotide el = Just $ updateAcc' el (Just acc)
  | otherwise = Nothing

isNucleotide :: Char -> Bool
isNucleotide 'A' = True
isNucleotide 'C' = True
isNucleotide 'G' = True
isNucleotide 'T' = True
isNucleotide _ = False

updateAcc' :: Char -> [(Nucleotide, Int)] -> [(Nucleotide, Int)]
updateAcc' 'A' [(A, a), (C, c), (G, g), (T, t)] = [(A, (a + 1)), (C, c), (G, g), (T, t)]
updateAcc' 'C' [(A, a), (C, c), (G, g), (T, t)] = [(A, a), (C, (c + 1)), (G, g), (T, t)]
updateAcc' 'G' [(A, a), (C, c), (G, g), (T, t)] = [(A, a), (C, c), (G, (g + 1)), (T, t)]
updateAcc' 'T' [(A, a), (C, c), (G, g), (T, t)] = [(A, a), (C, c), (G, g), (T, (t + 1))]
Run Code Online (Sandbox Code Playgroud)

对于第一个错误,基本上result来自updateAccupdateAcc返回Maybe [(Nucleotide, Int)]。因此,通过Just对结果进行处理,这不是将其解构为[(Nucleotide, Int)]吗?using 如何Just引入Maybe我在编译器的错误消息中看到的那一秒?

对于第二个错误,我的思考过程是类似的。updateAcc将其acc作为第二个参数,类型为Maybe [(Nucleotide, Int)]。我需要为 解构它updateAcc',所以我使用了Just,并遇到了同样的问题。

Dan*_*ner 5

您刚刚将包装和展开交换了。

nucleotideCounts xs = case result of
  Nothing -> Left "Error"
  Just result -> Right (Map.fromList result)
  ^^^^^^^^^^^                        ^^^^^^

             vvvvvvvvvv
updateAcc el (Just acc)
    | isNucleotide el = Just $ updateAcc' el acc
                                             ^^^
Run Code Online (Sandbox Code Playgroud)

应用该Just功能会增加一层Maybe;模式匹配针对Maybe具有Just模式的 a 删除一个层。我在这里所做的只是将您的两个Just函数应用程序移动到相应的模式匹配位置;这将“添加图层”转换为“删除图层”,净差异为两层。