在Haskell中实现字符串连接函数
我是Haskell的新手,尝试实现一个函数,该函数使用分隔符和列表返回串联字符串(类似于Python中的连接函数) 当我调用这个函数时,在Haskell中实现字符串连接函数,haskell,Haskell,我是Haskell的新手,尝试实现一个函数,该函数使用分隔符和列表返回串联字符串(类似于Python中的连接函数) 当我调用这个函数时,strJoin“|”[“foo”,“bar”]它会打印“foo | bar”,即使我希望结果是读“foo | bar” 如何调整模式匹配代码,使其对最后一个元素的工作方式不同?解决方案的问题是,第二个模式也将元素与一个元素匹配(在这种情况下,xs是[]),因此您将有一个额外的递归调用 strJoin sep arr = case arr of [] ->
strJoin“|”[“foo”,“bar”]
它会打印“foo | bar”
,即使我希望结果是读“foo | bar”
如何调整模式匹配代码,使其对最后一个元素的工作方式不同?解决方案的问题是,第二个模式也将元素与一个元素匹配(在这种情况下,
xs
是[]
),因此您将有一个额外的递归调用
strJoin sep arr = case arr of
[] -> ""
([x]) -> x
(x : xs) -> x ++ sep ++ strJoin sep xs
如果您不想自己为学习目的构建此应用程序,Data.List
具有interlate
用于此目的:
或者您可以同时使用
concat
和interspose
。问题在于代码的最后一行:
(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
我将把它作为一个练习来练习它是如何工作的。谢谢你的回答。我很想知道这是否可以通过模式匹配来实现。我为您添加了一个答案。@MichaelKohl感谢您添加了一个使用模式匹配的解决方案。我把雷德内布的解决方案标记为答案,因为他补充了所有的解释。再次感谢您告诉我有关插入函数的信息。我在谷歌上搜索了数据源。列表和插入函数()并意识到它的实现与我在这里收到的答案非常相似:-)我认为上述原因导致了strJoin“|”[“foo”]=“foo |”,我认为这不是预期的输出。基本情况应该是1,而不是2,IMO。谢谢你回答这个问题。我第一次看到@,我将找到它如何工作的解释。顺便说一句,您的第二个解决方案更具可读性。
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