Haskell 可能会列出元素操作

mig*_*der 0 haskell maybe

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

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

Run Code Online (Sandbox Code Playgroud)

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

我想出了这个

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

Run Code Online (Sandbox Code Playgroud)

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

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

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

che*_*ner 7

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

sum :: Num a => [a] -> Maybe a
sum [] = Nothing
sum [x] = Just x
sum (a:t) = fmap (a+) (sum t)
Run Code Online (Sandbox Code Playgroud)

这样,sum []永远不会被递归调用到达;任何非空列表都将首先命中基本情况sum [x]

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

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

请注意,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
Run Code Online (Sandbox Code Playgroud)

  • 在最后一个例子中,我们还可以将 `Just` 提升到递归之外,如 `sum [] = Nothing ; sum xs = Just (sum' xs)` 其中 `sum' [] = 0 ; sum'(a:t) = a + sum't`。这避免了“fmap”,因此它作为教学练习可能不太有用。 (2认同)