使用 maybe for pattern-matching of list 呈现错误
Using maybe for pattern-matching of list renders error
分解模式时应该如何使用Just
构造函数?
E.G:
如果我的模式是:(x1,x2,x3,....xn)
我将不得不用它的 Just
将模式的每个元素括起来?
我的问题:我正在尝试实现 Init 函数 "safely"。
我是否必须使用 Just
尾巴和头部也在第二行?
safeInit::[a]->Maybe [a]
safeInit (x:xs)=x: safeInit (Just xs) #Just x : safeInit Just xs ?
safeInit [x,y]=Just [x]
safeInit _ =Nothing
这里有两个问题:
- 您使用输入 a
Maybe [a]
拨打电话;和
- 您的第一个模式包含一个(严格的)超集,然后是第二个,因此第二个 永远不会 触发。
对于第一个问题,罪魁祸首在行中:
safeInit (x:xs) = x: safeInit (Just xs)
这里 safeInit
,需要一个列表(类型 [a]
),但是你将列表包装在 Just
构造函数中,因此你传递给它一个 Maybe [a]
值,而 safeInit
无法处理这个。所以我们可以改写为:
safeInit (x:xs) = x : safeInit xs
然而,这 不会 解决问题,因为现在我们在 a
上调用 "cons" (:
),并且 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
好吧,这取决于你想要什么语义。在 init
的情况下,一旦找到任何元素,您就会知道结果实际上是 Just
,即 Just init_xs
。然后您想要将当前的 x
添加到包含的列表中,而不更改 Just
的任何内容。最简单的方法是使用 Maybe
的 Functor
实例:
safeInit (x:xs) = (x:) <$> safeInit xs
但是请注意,这仅在您放入额外的基本情况时才有效,并且该子句必须在之前通用缺点之一:
safeInit :: [a] -> Maybe [a]
safeInit [_] = Just []
safeInit (x:xs) = (x:) <$> safeInit xs
safeInit [] = Nothing
另一种可能更容易理解的替代方法是 pattern-match 递归结果:
safeInit (x:xs) = case safeInit xs of
Just init_xs -> Just $ x : init_xs
Nothing -> Just []
safeInit [] = Nothing
根据 Elmex80s 的建议进行扩展,
safeInit :: [a] -> Maybe [a]
safeInit [] = Nothing
safeInit xs = Just (init xs)
分解模式时应该如何使用Just
构造函数?
E.G:
如果我的模式是:(x1,x2,x3,....xn)
我将不得不用它的 Just
将模式的每个元素括起来?
我的问题:我正在尝试实现 Init 函数 "safely"。
我是否必须使用 Just
尾巴和头部也在第二行?
safeInit::[a]->Maybe [a]
safeInit (x:xs)=x: safeInit (Just xs) #Just x : safeInit Just xs ?
safeInit [x,y]=Just [x]
safeInit _ =Nothing
这里有两个问题:
- 您使用输入 a
Maybe [a]
拨打电话;和 - 您的第一个模式包含一个(严格的)超集,然后是第二个,因此第二个 永远不会 触发。
对于第一个问题,罪魁祸首在行中:
safeInit (x:xs) = x: safeInit (Just xs)
这里 safeInit
,需要一个列表(类型 [a]
),但是你将列表包装在 Just
构造函数中,因此你传递给它一个 Maybe [a]
值,而 safeInit
无法处理这个。所以我们可以改写为:
safeInit (x:xs) = x : safeInit xs
然而,这 不会 解决问题,因为现在我们在 a
上调用 "cons" (:
),并且 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
好吧,这取决于你想要什么语义。在 init
的情况下,一旦找到任何元素,您就会知道结果实际上是 Just
,即 Just init_xs
。然后您想要将当前的 x
添加到包含的列表中,而不更改 Just
的任何内容。最简单的方法是使用 Maybe
的 Functor
实例:
safeInit (x:xs) = (x:) <$> safeInit xs
但是请注意,这仅在您放入额外的基本情况时才有效,并且该子句必须在之前通用缺点之一:
safeInit :: [a] -> Maybe [a]
safeInit [_] = Just []
safeInit (x:xs) = (x:) <$> safeInit xs
safeInit [] = Nothing
另一种可能更容易理解的替代方法是 pattern-match 递归结果:
safeInit (x:xs) = case safeInit xs of
Just init_xs -> Just $ x : init_xs
Nothing -> Just []
safeInit [] = Nothing
根据 Elmex80s 的建议进行扩展,
safeInit :: [a] -> Maybe [a]
safeInit [] = Nothing
safeInit xs = Just (init xs)