dai*_*ish 9 monads haskell list-comprehension list do-notation
我正在学习哈斯克尔。
\n我正在尝试查找列表中as与列表元素相加的元素bs,并将元素作为元组返回:
findSum2 :: [Int] -> [Int] -> [(Int,Int,Int)]\nfindSum2 as bs = [(a, a', b) | a <- as, a' <- as, b <- bs, a + a' == b]\nRun Code Online (Sandbox Code Playgroud)\n该代码有效。但为了学习 Haskell,我尝试将其重写为do-notation:
findSum2 :: [Int] -> [Int] -> [(Int,Int,Int)]\nfindSum2 as bs = do\n a <- as\n a' <- as \n b <- bs\n if a + a' == b then return (a, a', b) \n else return ()\nRun Code Online (Sandbox Code Playgroud)\n然后类型检查员向我抱怨:
\n \xe2\x80\xa2 Couldn't match type \xe2\x80\x98()\xe2\x80\x99 with \xe2\x80\x98(Int, Int, Int)\xe2\x80\x99\n Expected type: [(Int, Int, Int)]\n Actual type: [()]\nRun Code Online (Sandbox Code Playgroud)\n平心而论,我知道会的。但是由于我无法跳过Haskell 中的子句,那么我应该在子句中的语句else中放入什么?returnelse
谢谢。
\n您必须在子句中返回正确类型的内容else。它可以是空列表[],也可以是抽象值之一,例如mzero或empty。
或者您可以删除if表达式并使用该guard函数。
import Control.Monad (guard)
findSum2 :: [Int] -> [Int] -> [(Int,Int,Int)]
findSum2 as bs = do
a <- as
a' <- as
b <- bs
guard (a + a' == b)
return (a, a', b)
Run Code Online (Sandbox Code Playgroud)
通过此实现,您现在还可以将函数签名概括为:
findSum2 :: MonadPlus m => m Int -> m Int -> m (Int, Int, Int)
Run Code Online (Sandbox Code Playgroud)
您不能返回单位 ( ()),因为这意味着 和return (a, a', b)具有return ()不同的类型:第一个是[(Int, Int, Int)],而后者是[()]。
你可以做的是使用一个空列表,以防防护失败,所以:
findSum2 :: [Int] -> [Int] -> [(Int,Int,Int)]
findSum2 as bs = do
a <- as
a' <- as
b <- bs
if a + a' == b then return (a, a', b) else []Run Code Online (Sandbox Code Playgroud)