尝试使用Maybe

时间:2017-02-06 10:37:24

标签: haskell maybe

我制作了以下Haskell函数,用于检查列表中Orange的最大连续出现次数:

import Data.Maybe
data Fruit = Apple | Orange
findMaxSubStr :: [Fruit] -> Maybe Int

findMaxSubStr xs = val xs 0 0
    where val [] prev current = (max prev current)
          val (Apple:xs) prev current = val xs (max prev current) 0
          val (Orange:xs) prev current = val xs prev (current + 1)

我现在正在尝试集成Maybe类型,以防出现次数为0.例如,我希望[][Apple, Apple]生成Nothing而不是0 。我该怎么办?

此外,不是使用预建的max函数,如果我想创建自己的函数以检查最大值,最好的方法是什么?

2 个答案:

答案 0 :(得分:4)

我不明白为什么你这么做:只需使用scanl来确定“连续计数”,然后在其上应用maximum,以防结果为{{1} },返回0,否则Nothing

Just ...

这就是说我不明白你想要归还findMaxSubStr fruits | maxc == 0 = Nothing | otherwise = Just maxc where maxc = maximum counts counts = scanl f 0 fruits f x Orange = x+1 f _ _ = 0 的原因。在这种情况下,零是一个完全有效的答案。 Nothing通常用于返回某种“异常”答案。与可能无法找到元素的Maybe类似。

代码的工作原理如下:

首先我们执行findscanl通过列表传递某种 accumulator :对于每个元素,它使用累加器和列表中的对象调用函数(此处为scanl)。结果是“新”累加器。然后,此结果作为结果列表中的元素返回,并重新用于将累加器传递给下一个元素。所以一般来说它就像:

f

在这种情况下,累加器是到目前为止-- example of scanl for three elements (this is not its real implementation) scanl f acc0 [xa,xb,xc] = [acc1,acc2,acc3] where acc1 = f acc0 xa acc2 = f acc1 xb acc3 = f acc2 xc s 序列的长度 :所以Orange将映射到{{1此结果将存储在[Orange,Apple,Apple,Orange,Orange,Orange,Apple,Orange]

现在我们计算该列表[1,0,0,1,2,3,0,1]的{​​{1}}。因此,结果 - counts - 是maximum的最大值,因此是最长(不是当前)橙子序列的长度。

接下来在函数定义中,我们检查该值是否等于counts。如果是这种情况,我们会返回maxc。否则我们会返回counts

答案 1 :(得分:1)

在这里,您可以找到findMaxSubStr函数的定义,该函数使用折叠直接计算列表中最长橙子序列的长度,而不创建中间列表:

import Data.List (foldl')

findMaxSubStr :: [Fruit] -> Maybe Int
findMaxSubStr fruits =
  case numOranges of
    0 -> Nothing
    n -> Just n
  where
    numOranges = uncurry max $ foldl' countOranges (0, 0) fruits
    countOranges t Orange = (1+) <$> t
    countOranges (x,y) _ = (max x y, 0)

this page中,您可以找到有关何时使用foldl'与使用foldrfoldl的讨论,以及显示这些折叠功能如何工作的示例。

元组用于跟踪橙色序列的长度。第一个值保持找到的最长序列的长度,第二个元素保存当前序列的长度。

where块的原始实现是:

where
  numOranges = fst $ foldl' countOranges (0, 0) fruits
  countOranges (x, y) Orange = let y' = y+1 in (max x y', y')
  countOranges (x, _) _  = (x, 0)

我在@Ryan建议之后编辑了答案(请参阅下面的评论),以下是一些描述解决方案如何运作的说明:

countOranges t Orange = (1+) <$> t利用了2元组是仿函数的事实,<$>运算符将作为第一个参数传递的函数(在我们的例子中是(1+))应用到第二个元素2元组。因此,在计数器(x, y)中,我们在查找橙子的同时增加y,而不会触及x,即我们正在计算当前橙色序列的长度(当我们找到一个时)。

当我们找到苹果时,countOranges (x,y) _ = (max x y, 0)会更新x中的(x,y)并将y重置为0。您可以看到x将保留到目前为止发现的最长橙子序列的长度。

如果最长的橙子序列出现在水果列表的末尾,则不会发生前一段中描述的x更新。这就是我们仍然需要numOranges = uncurry max $ ...(x, y)返回的foldl'元组中获取最大值的原因。