使用可能用于列表渲染错误的模式匹配

时间:2018-04-11 12:08:23

标签: haskell pattern-matching maybe

在分解模式时,我应该如何使用Just构造函数?  
E.G:
如果我的模式是:(x1,x2,x3,....xn)我将必须用模式Just包围模式的每个元素?

我的问题:我正在尝试实施初始化功能"安全"。我是否必须使用Just作为尾部和在第二行也是头?

safeInit::[a]->Maybe [a]
safeInit (x:xs)=x: safeInit (Just xs) #Just x : safeInit Just xs ?
safeInit [x,y]=Just [x]
safeInit _ =Nothing

3 个答案:

答案 0 :(得分:5)

这里有两个问题:

  • 您拨打Maybe [a]作为输入进行了通话;和
  • 你的第一个模式包含一个(严格)超集然后是第二个模式,所以第二个模式将从不开火。

对于第一个问题,罪魁祸首在于:

safeInit (x:xs) = x: safeInit (Just xs)

此处safeInit需要一个列表(类型[a]),但是您将列表包装在Just构造函数中,因此您将其传递给Maybe [a]值,并且safeInit无法处理此问题。所以我们可以将其重写为:

safeInit (x:xs) = x : safeInit xs

然而,这将 解决问题,因为现在我们称之为" cons" :a上的{Maybe [a]},而且该功能再次无法处理此问题。我们首先要检查递归调用是否产生safeInit,然后在x之前添加并将其重新包装在Just中,我们可以使用fmap执行此操作:

safeInit (x:xs) = fmap (x:) (safeInit xs)

对于第二个问题,我们可以重新安排条款:

safeInit :: [a] -> Maybe a
safeInit [x, _] = Just [x]
safeInit (x:xs) = fmap (x:) (safeInit xs)
safeInit [] = Nothing

尽管如此,这种方法仍然存在问题:它是相当低效的,因为我们为所有元素(除了最后一个元素)打开并包装Just元素,因为它没有被优化。此外,如果我们处理无限列表,我们将陷入无限循环。我们可以通过使用内部函数来改进它,它计算init,因为我们知道init是有效的。例如:

safeInit :: [a] -> Maybe a
safeInit (x:xs) = Just (go x xs)
    where go _ [] = []
          go x (x2:xs) = x : go x2 xs
safeInit [] = Nothing

答案 1 :(得分:4)

嗯,这取决于你想要的语义。如果是init,一旦找到任何元素,您知道结果实际上将是Just,即Just init_xs。然后,您希望将当前x添加到包含列表中,而不是更改Just的任何内容。最简单的方法是使用Maybe的{​​{1}}实例:

Functor

但是请注意,这只有在你加入一个额外的基础案例时才有效,并且该子句必须在之前通用的

safeInit (x:xs) = (x:) <$> safeInit xs

可能更容易理解的替代方法是对递归结果进行模式匹配:

safeInit :: [a] -> Maybe [a]
safeInit [_] = Just []
safeInit (x:xs) = (x:) <$> safeInit xs
safeInit []  = Nothing

答案 2 :(得分:3)

扩展Elmex80s的建议,

safeInit :: [a] -> Maybe [a]
safeInit [] = Nothing
safeInit xs = Just (init xs)