1

我试图在haskell中交换列表的第一个和最后一个元素。我已经尝试过模式匹配、表达式、函数等。这是我最后一次尝试:

cambio xs = [ cabeza++([x]++cola)|x<-xs, cabeza <- init x, cola <- last x, drop 1 x, drop 0 ([init x])]

我的编译器抛出下一个错误:

Couldn't match expected type `Bool' with actual type `[a0]'
    In the return type of a call of `drop'
    In the expression: drop 1 x
    In a stmt of a list comprehension: drop 1 x

谁能帮我?我已经尝试这样做了 2 天

4

3 回答 3

4

这里有一些提示:

  1. 你不能用列表理解来解决这个问题。
  2. 确定基本(琐碎)案例 - 空列表和一个元素列表。写出涵盖这些情况的方程式。
  3. 在所有其他情况下,输入列表的长度将 >= 2。您想要的列表是

    [z] ++ xs ++ [a]

其中 z 是最后一个元素,a 是输入列表的第一个元素,xs 是输入的中间部分。

现在告诉我(或你自己),如果输入字符串的长度为 k,xs 将有多长?

  1. 写出包含超过 1 个元素的列表情况的等式。您可以使用 head、last、length、drop 或 take 等函数。
于 2013-03-17T23:44:18.070 回答
2

我认为列表不是执行此操作的最佳数据结构,但在这里:

swap list = last list : (init . tail $ list) ++ [head list]

这将需要遍历列表,并且在长列表中会很慢。这就是链表的本质。


更新了提问者的基本案例:

swap [] = [] 
swap [a] = [a] 
swap list = last list : (init . tail $ list) ++ [head list] 
于 2013-03-17T23:43:38.260 回答
2

这是一件相当简单的事情,尤其是使用标准列表函数:

swapfl [] = []
swapfl [x] = [x]
swapfl (x:xs) = (last xs : init xs) ++ [x]

或者没有它们(尽管这不太可读,通常不做,也不推荐):

swapfl' [] = []
swapfl' [x] = [x]
swapfl' (x:xs) = let (f, g) = sw x xs in f:g
  where sw k [y] = (y, [k])
        sw k (y:ys) = let (n, m) = sw k ys in (n, y:m)

或许多其他方式之一。

我希望这会有所帮助......我知道我没有做太多解释,但坦率地说,就这个功能而言,很难确切地说出你遇到了什么问题,因为你似乎也完全误解了列表理解。我认为如果我解释这些可能是最有益的?

为什么这不能通过列表理解来解决?我强硬他们就像函数但有不同的形式

并不真地。列表推导式对于轻松定义列表很有用,并且它们与数学中的集合构建符号非常密切相关。这对于这个特定的应用程序没有用处,因为虽然它们非常擅长修改列表的元素,但推导式并不擅长重新排序列表。

在理解中,您包含三个部分:列表中元素的定义、一个或多个输入列表以及零个或多个谓词:

[ definition | x <- input1, y <- input2, predicate1, predicate2 ]

该定义描述了我们正在制作的列表的单个元素,根据输入中的箭头指向的变量(在本例中为 x 和 y)。每个输入在箭头右侧都有一个列表,在左侧有一个变量。我们正在制作的列表中的每个元素都是通过将输入列表中的每个元素组合提取到这些变量中来构建的,并使用这些值评估定义部分。例如:

[ x + y | x <- [1, 3], y <- [2, 4] ]

这会产生:

[1 + 2, 1 + 4, 3 + 2, 3 + 4] == [3, 5, 5, 7]

此外,您可以包含谓词,类似于过滤器。每个谓词都是根据输入元素定义的布尔表达式,并且只要有新的列表元素,就会对每个谓词进行评估。如果任何谓词结果为假,则这些元素不会放在我们正在制作的列表中。

让我们看看你的代码:

cambio xs = [ cabeza++([x]++cola) | x<-xs, cabeza <- init x, cola <- last x,
                                    drop 1 x, drop 0 ([init x])]

这种理解的输入是x <- xscabeza <- init xcola <- last x。第一个意味着其中的每个元素xs都将用于为新列表定义元素,并且每个元素都将被命名x。另外两个没有任何意义,因为initandlast是 type [a] -> a,但是在箭头的右侧,所以必须是列表,并且x必须是列表的元素,因为它在箭头的左侧,所以在为了使它甚至可以编译, xs 必须是 type [[[a]]],我敢肯定这不是您想要的。

您使用的谓词是drop 1 xand drop 0 [init x]。我有点理解你试图用第一个做什么,删除列表的第一个元素,但这不起作用,因为x它只是列表的一个元素,而不是列表本身。在第二个中,drop 0表示“从以下列表的开头删除零个元素”,这绝对不会做任何事情。在任何一种情况下,将类似的东西放在谓词中都行不通,因为谓词需要是一个布尔值,这就是你得到编译器错误的原因。这是一个例子:

pos xs = [ x | x <- xs, x >= 0 ]

这个函数接受一个数字列表,删除所有负数,并返回结果。谓词是x >= 0,它是一个布尔表达式。如果表达式的计算结果为 false,则正在计算的元素会从结果列表中过滤掉。

您使用的元素定义是cabeza ++ [x] ++ cola. 这意味着“结果列表中的每个元素本身就是一个列表,由列表中的所有元素组成cabeza,后跟一个包含 的元素x,然后是列表中的所有元素cola”,这似乎与您的意图相反为了。请记住,管道字符之前的部分定义了单个元素,而不是列表本身。另外,请注意,将方括号括在变量周围会创建一个包含该变量的新列表,并且仅包含该变量。如果你说y = [x],这意味着 y 包含单个元素 x,并且没有说明 x 是否是列表。

我希望这有助于澄清一些事情。

于 2013-03-18T02:39:17.343 回答