简体   繁体   English

使用也许用于列表的模式匹配会出现错误

[英]Using maybe for pattern-matching of list renders error

How should i use the Just constructor when decomposing a pattern? 分解模式时应如何使用Just构造函数?
EG: 例如:
If my pattern is : (x1,x2,x3,....xn) i will have to enclose each element of the pattern with its Just ? 如果我的模式是: (x1,x2,x3,....xn)我将不得不用其Just包围模式的每个元素。

My problem : i am trying to implement the Init function "safely". 我的问题:我试图“安全”地实现Init函数。
Do i have to use the Just for the tail and for the head too in the second line? 在第二行中,我是否也必须将Just用作尾巴和头部?

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

There are two problems here: 这里有两个问题:

  • you make a call with as input a Maybe [a] ; 您使用Maybe [a]作为输入进行呼叫; and
  • your first pattern contains a (strict) superset then the second, so the second one will never fire. 您的第一个模式包含一个(严格)超集,然后包含第二个,因此第二个将永远不会触发。

For the first problem, the culprit is in the line: 对于第一个问题,罪魁祸首是:

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

Here safeInit , expects a list (type [a] ), but you wrap the list in the Just constructor, hence you pass it a Maybe [a] value, and the safeInit can not handle this. 这里safeInit需要一个列表(类型[a] ),但是您将列表包装在Just构造函数中,因此您将其传递了一个Maybe [a]值,而safeInit无法处理该值。 So we can rewrite it to: 因此我们可以将其重写为:

safeInit (x:xs) = x : safeInit xs

This will however not solve the problem, since now we call the "cons" ( : ) on an a , and Maybe [a] , and again, the function can not handle this. 然而,这将解决这个问题,因为现在我们所说的“缺点”( : :上的a ,并且Maybe [a]并再次,该功能无法处理这个问题。 We will first have to inspect whether the recursive call produces a safeInit , and then prepend the x and rewrap it in a Just , we can do this with an fmap : 我们首先必须检查递归调用是否产生了safeInit ,然后将x放在前面并重新包装在Just ,我们可以使用fmap做到这fmap

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

For the second problem, we can rearrange the clauses: 对于第二个问题,我们可以重新排列以下子句:

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

Nevertheless there are still problems with this approach: it is rather inefficient, since we unwrap and wrap the Just element for all elements (except the last one), given that is not optimized. 但是,这种方法仍然存在问题:这种方法效率很低,因为我们会为所有元素(最后一个除外)解包并包装Just元素,但前提是未优化。 Furthermore in case we process an infinite list, we will get stuck in an infinite loop. 此外,如果我们处理无限列表,我们将陷入无限循环。 We can improve it, by using an inner function, that calculates the init given we know for sure that that init is valid. 我们可以通过使用内部函数来改进它,该函数可以计算已知的init来确定该init有效。 For example: 例如:

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

Well, it depends on what semantics you want. 好吧,这取决于您想要什么语义。 In case of init , once you've found any element at all, you know the result will actually be Just anyway, namely, Just init_xs . 在使用init情况下,一旦找到任何元素,您将知道结果实际上Just ,即Just init_xs You then want to prepend the current x to the included list, not changing anything about the Just . 然后,您想将当前x放在列表的前面,而不更改Just任何内容。 The easiest way to do that is to use Maybe 's Functor instance: 最简单的方法是使用MaybeFunctor实例:

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

Note however that this only works if you put in an extra base case, and the clause must go before the generic cons one: 但是请注意,这仅在放入额外基本情况的情况下有效,并且该子句必须位于通用缺点之前

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

An alternative that's perhaps easier to understand is to pattern-match on the recursive result: 也许更容易理解的替代方法是对递归结果进行模式匹配:

safeInit (x:xs) = case safeInit xs of
      Just init_xs -> Just $ x : init_xs
      Nothing -> Just []
safeInit [] = Nothing

Expanding on Elmex80s's suggestion, 扩展Elmex80的建议,

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM