在分解模式时,我应该如何使用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
答案 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)