我目前正在学习 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来自updateAcc。updateAcc返回Maybe [(Nucleotide, Int)]。因此,通过Just对结果进行处理,这不是将其解构为[(Nucleotide, Int)]吗?using 如何Just引入Maybe我在编译器的错误消息中看到的那一秒?
对于第二个错误,我的思考过程是类似的。updateAcc将其acc作为第二个参数,类型为Maybe [(Nucleotide, Int)]。我需要为 解构它updateAcc',所以我使用了Just,并遇到了同样的问题。
您刚刚将包装和展开交换了。
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函数应用程序移动到相应的模式匹配位置;这将“添加图层”转换为“删除图层”,净差异为两层。