0

我正在尝试编写一个函数,它将字符串中的单个字符添加到字符串列表中,例如

combine ", !" ["Hello", "", "..."] = ["Hello,", " ", "...!"]

我试过这个:

combine :: String -> [String] -> [String]
combine (y:ys) (x:xs) =
[x:y, combine ys xs]
4

3 回答 3

2

一个简单的就是

 combine :: [Char] -> [String] -> [String]
 combine [] _ = []
 combine _ [] = []
 combine (c:cs) (x:xs) = x ++ [c] : combine cs xs

或者更简单地使用zipWith

 combine :: [Char] -> [String] -> [String]
 combine = zipWith (\c x -> x ++ [c])

我必须做一些额外的工作才能让它工作。我给你分解一下。

首先,我将函数的类型指定为[Char] -> [String] -> [String]. 我可以使用String第一个参数,但您在概念上操作的是字符列表和字符串列表,而不是字符串和字符串列表。

接下来,我必须为这个函数指定边缘情况。当任一参数为空列表时会发生什么[]?简单的答案是然后结束计算,所以我们可以写

combine [] _ = []
combine _ [] = []

这里_匹配任何东西,但是因为它没有在返回值中使用而将其丢弃。

接下来,对于函数的实际主体,我们要获取第一个字符和第一个字符串,然后将该字符附加到字符串的末尾:

combine (c:cs) (x:xs) = x ++ [c]

cs但这对or没有任何xs作用,我们的列表的其余部分(甚至不会使用上面的类型签名编译)。我们需要继续,因为我们正在生成一个列表,这通常是使用前置运算符完成的:

combine (c:cs) (x:xs) = x ++ [c] : combine cs xs

然而,这是一种非常常见的模式,以至于有一个辅助函数zipWith可以为我们处理边缘情况。它的类型签名是

zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]

它同时遍历两个输入列表,将相应的元素传递给提供的函数。由于我们要应用的函数是\c x -> x ++ [c](变成一个 lambda 函数),我们可以把它放到zipWithas

combine cs xs = zipWith (\c x -> x ++ [c]) cs xs

但是 Haskell 会让我们在可能的情况下放弃参数,所以我们可以将它减少到

combine :: [Char] -> [String] -> [String]
combine = zipWith (\c x -> x ++ [c])

就是这样!

于 2013-10-18T16:33:16.140 回答
2

当您想逐个元素地组合列表时,通常是zip您正在查看的。在这种情况下,你确切地知道你想如何组合元素——这使它成为一个zipWith.

zipWith采用“组合函数”,然后使用所述组合函数创建一个组合两个列表的函数。让我们调用您的“组合”函数append,因为它会在字符串的末尾添加一个字符。你可以这样定义它:

append char string = string ++ [char]

你明白这是如何工作的吗?例如,

append 'e' "nic" = "nice"

或者

append '!' "Hello" = "Hello!"

现在我们有了它,回想一下它zipWith采用“组合函数”,然后创建一个使用该函数组合两个列表的函数。所以你的功能很容易实现为

combine = zipWith append

它将append按您提供的列表中的每个元素执行,如下所示:

combine ", !" ["Hello", "", "..."] = ["Hello,", " ", "...!"]
于 2013-10-18T16:31:29.553 回答
0

你很亲密。你所拥有的有几个问题。

y 具有 Char 类型,x 具有 String 类型,它是 [Char] 的别名。这意味着您可以使用 y : x 将 y 添加到列表的顶部,但不能使用相同的:运算符将 y 添加到列表的末尾。相反,您将 y 放入列表并加入列表。

x ++ [y]

还必须有一个基本情况,否则这个递归将继续,直到它在任何一个列表中都没有元素并崩溃。在这种情况下,我们可能没有想要添加的任何内容。

combine [] [] = []

最后,一旦我们创建了元素y ++ [x],我们希望将它添加到我们计算的其余项目的顶部。因此,我们:习惯将其添加到我们的列表中。

combine :: String -> [String] -> [String]
combine [] [] = []
combine (x : xs) (y : ys) = (y ++ [x]) : (combine xs ys)

关于此代码的一个注意事项,如果字符串中的字符数与列表中的字符串数不同,那么这将崩溃。您可以通过多种方式处理这种情况,bheklilr 的回答解决了这个问题。

kqr 的答案也很完美,可能是实践中最好的答案。

于 2013-10-18T16:44:02.163 回答