List Haskell(:)和(+;+;)差异

List Haskell(:)和(+;+;)差异,list,haskell,syntax,List,Haskell,Syntax,我为这样的问题感到抱歉。我不太确定Haskell中:和++操作符的区别 x:y:[] = [x,y] 也 至于引起我这个问题的反向函数 reverse ::[a]->[a] reverse [] = [] reverse (x:xs) = reverse(xs)++[x] 为什么下面的方法不起作用 reversex ::[Int]->[Int] reversex [] = [] reversex (x:xs) = reversex(xs):x:[] 给出一个类型错误。:在列

我为这样的问题感到抱歉。我不太确定Haskell中
++
操作符的区别

x:y:[] = [x,y]  

至于引起我这个问题的反向函数

reverse ::[a]->[a]
reverse [] = []
reverse (x:xs) = reverse(xs)++[x]
为什么下面的方法不起作用

reversex ::[Int]->[Int]
reversex [] = []
reversex (x:xs) = reversex(xs):x:[]

给出一个类型错误。

:在列表中使用一个元素

++附加两个列表

前者有两种类型

a -> [a] -> [a]
[a] -> [a] -> [a]
而后者则有类型

a -> [a] -> [a]
[a] -> [a] -> [a]

运算符被称为“cons”运算符,用于将head元素前置到列表中。因此,
[]
是一个列表,
x:[]
x
前面加了一个空列表,使列表成为一个列表。然后,如果您选择cons
y:[x]
则会得到与
y:x:[]
相同的列表
[y,x]

++
运算符是列表串联运算符,它将两个列表作为操作数,并将它们“组合”到一个列表中。因此,如果您有列表
[x]
和列表
[y]
,那么您可以像这样连接它们:
[x]+[y]
以获得
[x,y
]

请注意,
接受一个元素和一个列表,而
++
接受两个列表

至于你的代码不起作用

reversex ::[Int]->[Int]
reversex [] = []
reversex (x:xs) = reversex(xs):x:[]

reverse函数的计算结果为一个列表。由于
运算符没有将列表作为其第一个参数,因此
reverse(xs):x
无效。但是
reverse(xs)++[x]
是有效的。

与(++)

也许我想深入研究一下但是, 据我所知,如果你尝试连接 使用
(++)
列出,例如:

[1, 2, 3] ++ [4, 5]
(++)
必须遍历完整的左侧列表。 看一看这张照片就知道了 更清楚了

(++) :: [a] -> [a] -> [a]
(++) []     ys = ys
(++) (x:xs) ys = x : xs ++ ys
因此,最好避免使用
(++)
,因为每次调用
reverse(xs)+[x]
列表越来越大(或越来越小,具体取决于 无论如何,程序只需遍历另一个程序 (每次通话时都列出)

示例:

假设我通过连接实现了建议的反向

reversex ::[Int]->[Int]
reversex [] = []
reversex (x:xs) = reversex(xs)++[x]
反转列表[1,2,3,4]看起来有点像这样:

reversex [1, 2, 3, 4]
reversex [2, 3, 4]               ++ [1]
reversex [3, 4]           ++ [2] ++ [1]
reversex [4]       ++ [3] ++ [2] ++ [1]
reversex [] ++ [4] ++ [3] ++ [2] ++ [1]
         [] ++ [4] ++ [3] ++ [2] ++ [1]
         [4]       ++ [3] ++ [2] ++ [1]
         [4, 3]           ++ [2] ++ [1]
         [4, 3, 2]               ++ [1]
         [4, 3, 2, 1]
使用cons运算符(:)的尾部递归

处理调用堆栈的一种方法是添加一个。 (仅仅添加一个累加器并不总是可能的,但大多数 一个人处理的递归函数是,因此可以 变成

在累加器的帮助下,可以做出这个例子 使用cons操作符
(:)
工作。 累加器--
ys
在我的示例中--累加当前结果并作为参数传递。因为有了累加器,我们现在可以 使用cons运算符通过附加 每次都是我们最初名单的负责人

reverse' :: (Ord a) => [a] -> [a] -> [a]
reverse' (x:xs) ys = reverse' xs (x:ys)
reverse' [] ys     = ys
这里有一件事需要注意

累加器是一个额外的参数。我不知道哈斯克尔 提供默认参数,但在这种情况下最好, 因为您总是使用空列表调用此函数 就像累加器一样:
reverse'[1,2,3,4][]

有很多关于尾部递归的文献,我 当然有很多类似的问题 堆栈交换/堆栈溢出。如果你发现任何错误,请纠正我

亲切问候,

编辑1

威尔·内斯为你们中感兴趣的人指出了一些真正好答案的链接:

编辑2

嗯。 多亏了德弗尔和他的纠正,我想我理解哈斯克尔 好一点

1.<代码>$超出了我的理解范围。在我所有的测试中,似乎都是这样 让事情变得更糟

2.正如德弗尔指出的那样: 表示将
(:)
应用到
x
y
的thunk在语义上与
x:y
相同,但占用更多内存。这对cons操作员来说是特别的 (和懒惰的构造函数)并且没有必要以任何方式强制执行

3.如果我用一个非常相似的函数求一个列表的整数的和, 通过模式或
seq
功能进行严格评估 如果使用得当,将防止堆栈过大。e、 g:

sumUp' :: (Num a, Ord a) => [a] -> a -> a
sumUp' (x:xs) !y = reverse' xs (x + y)
sumUp' [] y      = y
注意y前面的砰砰声。我在ghci试过了
占用更少的内存。

cons
倾向于使用类型构造函数而不是运算符。这里的示例是
可以在
let..in..
表达式中使用,但
++
不能

let x : xs = [1, 2, 3] in x -- known as type deconstructing
将返回1,但

let [x] ++ [y, z] = [1, 2, 3] in x
将返回一个不在范围x中的错误
变量

为了让它更简单,可以这样想
cons

data List a = Cons a (List a) -- is equvalent with `data [a] = a:[a]`

此外,如果要使用cons反转阵列,请执行以下操作。下面是一个例子,知识来自Prolog

import Data.Function

reversex1 [] = []
reversex1 arr = reversex arr []

reversex [] arr = arr
reversex (x:xs) ys = reversex xs (x:ys)

main = do
    reversex1 [1..10] & print

你可以稍微改变一下,得到正确的结果

reversex ::[Int]->[Int] # comment this line
reversex [] = []
reversex (x:xs) = reversex(xs) ++ x : []

对于遇到挑战的Lisp词汇表,“cons”构造一个新的列表节点,并将其添加到列表的开头。作为补充说明,您可以(也应该)不使用括号进行调用:
reverse(x:xs)=reverse xs++[x]
,否则在使用具有多个参数的函数时,您会被绊倒。不要调用
func(arg)之类的函数
。那是可怜的哈斯克尔。始终调用函数,如
func arg
。带有清晰空格的代码使代码更加自信和可读。@AJFarmarfunc-arg确实比func(arg)更正确,但我认为f(x)通常比fx更可读,因为它与大多数其他语言以及指定函数的数学方法相匹配。所以我想说“更自信、更具可读性”是一个观点问题。@icc97,上下文。在编写Haskell代码的上下文中,
func(arg)
与使用Haskell从不延迟延迟构造函数的应用程序一样令人困惑(因为从来没有延迟构造函数)