我是Haskell的新手并尝试实现一个函数,该函数使用分隔符和列表来返回连接的字符串(类似于Python中的join函数)
strJoin sep arr = case arr of
[] -> ""
(x : xs) -> x ++ sep ++ strJoin sep xs
当我调用此函数strJoin "|" ["foo", "bar"]
时,它会打印"foo|bar|"
,即使我希望结果为"foo|bar"
如何调整模式匹配代码,使其对最后一个元素的工作方式不同?
答案 0 :(得分:4)
问题在于代码的最后一行:
(x : xs) -> x ++ sep ++ strJoin sep xs
模式x : xs
的含义是x
将匹配单个元素,即列表的第一个元素,xs
将与列表匹配,即列表除了第一个元素之外的所有元素。此列表可以为空。具体来说,如果arr
包含单个元素,则x
将与该单个元素匹配,而xs
将与列表的其余部分(即空列表)匹配。但是,在右边,你实际上有:
x ++ sep ++ strJoin sep []
相当于
x ++ sep ++ ""
又与
相同x ++ sep
这解释了您的功能的行为。那么我们如何解决这个问题呢?一种解决方案是尝试更改该案例的模式,以便不在具有单个元素的列表上使用该规则。一种方法是这样:
(x : xs @ (_ : _)) -> x ++ sep ++ strJoin sep xs
此处xs @ (_ : _)
将与非空列表匹配。我将把这个解释留作练习。
所以现在该规则不会像我们想要的那样在单个元素列表上使用,但问题是这些列表不再有规则。所以我们需要添加一个新的。以下是:
[x] -> x
所以把它们放在一起:
strJoin sep arr = case arr of
[] -> ""
(x : xs @ (_ : _)) -> x ++ sep ++ strJoin sep xs
[x] -> x
当然还有很多其他方法可以做到这一点,其中一个是:
strJoin sep arr = case arr of
[] -> ""
[x] -> x
(x : xs) -> x ++ sep ++ strJoin sep xs
我会把它作为一个练习如何运作。
答案 1 :(得分:3)
您的解决方案的问题是第二个模式也匹配具有一个元素的元素(在这种情况下override func viewWillLayoutSubviews() {
tabBar.itemPositioning = UITabBarItemPositioning.fill
}
是xs
),因此您将有一个额外的递归调用。
[]
如果您不想出于学习目的自行构建,strJoin sep arr = case arr of
[] -> ""
([x]) -> x
(x : xs) -> x ++ sep ++ strJoin sep xs
为此目的Data.List
:
https://www.haskell.org/hoogle/?hoogle=intercalate
intercalate
或者您可以同时使用import Data.List
intercalate "|" ["foo", "bar"]
和concat
。