我正在学习Haskell。
我正在尝试查找列表as的元素,这些元素与列表bs的元素相加,并以元组的形式返回这些元素:
findSum2 :: [Int] -> [Int] -> [(Int,Int,Int)]
findSum2 as bs = [(a, a', b) | a <- as, a' <- as, b <- bs, a + a' == b]代码起作用了。但为了学习Haskell,我尝试将其重写为do-notation:
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 return ()然后类型检查器向我抱怨:
• Couldn't match type ‘()’ with ‘(Int, Int, Int)’
Expected type: [(Int, Int, Int)]
Actual type: [()]说句公道话,我就知道会这样。但是既然我不能跳过Haskell中的else子句,那么我应该在else子句的return语句中放什么呢?
谢谢。
发布于 2021-11-16 12:34:20
您必须在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)使用此实现,您现在还可以将您的函数签名泛化为:
findSum2 :: MonadPlus m => m Int -> m Int -> m (Int, Int, Int)发布于 2021-11-16 11:46:43
您不能返回单元(()),因为这意味着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 []https://stackoverflow.com/questions/69988537
复制相似问题