[英]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: 这里有两个问题:
Maybe [a]
; 您使用Maybe [a]
作为输入进行呼叫; and 和 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: 最简单的方法是使用Maybe
的Functor
实例:
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.