首页 > 解决方案 > Haskell Maybe 列表元素操作

问题描述

我正在学习 Haskell 中的列表操作,现在我正在尝试可能列表类型的各种列表操作。目前,我在 Haskell 的列表中实现了元素总和

sum :: Num a => [a] -> a
sum [] = 0
sum (a:t) = a + sum t

现在我想做同样的事情,但不是返回值,而是返回一个 Maybe 类型。当给定的列表为空时,它应该返回 Nothing。

我想出了这个

sum :: Num a => [a] -> Maybe a
sum [] = Nothing
sum (a:t) = fmap (a+) (sum t)

但是给出的所有非空列表的结果都没有结果。

据我了解,给出的列表最终将与空列表进行模式匹配,因此返回 Nothing。

我该如何解决这个问题,以便它返回预期值和可能类型。我不知道如何使它像上面的正常 sum 实现一样递归地工作,所以我想应该有另一种方法。如果只导入 Prelude 模块,我会更喜欢,因为我仍在尝试吸收 Prelude 模块中的内容。

标签: haskellmaybe

解决方案


问题是您的递归函数始终使用空列表作为基本案例,因此您的基本案例值始终 Nothing为. Nothing如果“root”调用采用空列表,您只想返回。否则,您想使用单例列表作为基本案例。

sum :: Num a => [a] -> Maybe a
sum [] = Nothing
sum [x] = Just x
sum (a:t) = fmap (a+) (sum t)

这样,sum []递归调用将永远无法到达;任何非空列表将sum [x]首先达到基本情况。

另一种组织方法是使用原始的总函数作为仅对非空列表求和的助手,并单独处理空列表。

sum :: Num a => [a] -> Maybe a
sum [] = Nothing
sum xs = sum' xs
  where sum' [] = Just 0
        sum' (a:t) = fmap (a+) (sum' t)

请注意,sum'可以在空列表上调用,但前提是它最初是在非空列表上调用的。

正如@chi 指出的那样,辅助函数根本不需要使用Maybe;由于它只对非空列表求和,因此您可以fmap正常跳过使用和求和列表;只有最终结果需要包含在Just

sum :: Num a => [a] -> Maybe a
sum [] = Nothing
sum xs = Just (sum' xs)
         where sum' [] = 0
               sum' (a:t) = a + sum' t

推荐阅读