在Haskell中实现String join函数

时间:2016-09-15 01:41:08

标签: haskell

我是Haskell的新手并尝试实现一个函数,该函数使用分隔符和列表来返回连接的字符串(类似于Python中的join函数)

strJoin sep arr = case arr of
  [] -> ""
  (x : xs) -> x ++ sep ++ strJoin sep xs

当我调用此函数strJoin "|" ["foo", "bar"]时,它会打印"foo|bar|",即使我希望结果为"foo|bar"

如何调整模式匹配代码,使其对最后一个元素的工作方式不同?

2 个答案:

答案 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