首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Do-notation和list monad

Do-notation和list monad
EN

Stack Overflow用户
提问于 2021-11-16 11:44:18
回答 2查看 125关注 0票数 9

我正在学习Haskell。

我正在尝试查找列表as的元素,这些元素与列表bs的元素相加,并以元组的形式返回这些元素:

代码语言:javascript
复制
findSum2 :: [Int] -> [Int] -> [(Int,Int,Int)]
findSum2 as bs = [(a, a', b) | a <- as, a' <- as, b <- bs, a + a' == b]

代码起作用了。但为了学习Haskell,我尝试将其重写为do-notation:

代码语言:javascript
复制
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 ()

然后类型检查器向我抱怨:

代码语言:javascript
复制
   • Couldn't match type ‘()’ with ‘(Int, Int, Int)’
      Expected type: [(Int, Int, Int)]
        Actual type: [()]

说句公道话,我就知道会这样。但是既然我不能跳过Haskell中的else子句,那么我应该在else子句的return语句中放什么呢?

谢谢。

EN

回答 2

Stack Overflow用户

发布于 2021-11-16 12:34:20

您必须在else子句中返回正确类型的内容。它可以是空列表[],也可以是抽象值之一,如mzeroempty

或者,您可以删除if表达式并使用guard函数。

代码语言:javascript
复制
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)

使用此实现,您现在还可以将您的函数签名泛化为:

代码语言:javascript
复制
findSum2 :: MonadPlus m => m Int -> m Int -> m (Int, Int, Int)
票数 8
EN

Stack Overflow用户

发布于 2021-11-16 11:46:43

您不能返回单元(()),因为这意味着return (a, a', b)return ()具有不同的类型:第一个是[(Int, Int, Int)],而后者是[()]

你能做的就是使用一个空的列表,以防守卫失败,所以:

代码语言:javascript
复制
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 []
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69988537

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档