Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 是否存在类似(xs:x)的东西_Haskell - Fatal编程技术网

Haskell 是否存在类似(xs:x)的东西

Haskell 是否存在类似(xs:x)的东西,haskell,Haskell,我是哈斯克尔的新手。我知道我可以通过以下操作创建一个反向函数: reverse :: [a] -> [a] reverse [] = [] reverse (x:xs) = (Main.reverse xs) ++ [x] 是否存在这样一种情况,即(xs:x)(与元素连接的列表,即x是列表中的最后一个元素),因此我将最后一个列表元素放在列表的前面 rotate :: [a] -> [a] rotate [] = [] rotate (xs:x) = [x] ++ xs 当我试图编

我是哈斯克尔的新手。我知道我可以通过以下操作创建一个
反向
函数:

reverse :: [a] -> [a]
reverse [] = []
reverse (x:xs) = (Main.reverse xs) ++ [x]
是否存在这样一种情况,即
(xs:x)
(与元素连接的列表,即
x
是列表中的最后一个元素),因此我将最后一个列表元素放在列表的前面

rotate :: [a] -> [a]
rotate [] = []
rotate (xs:x) = [x] ++ xs
当我试图编译包含此函数的程序时,会出现以下错误:

Occurs check: cannot construct the infinite type: a = [a]
When generalising the type(s) for `rotate'
head :: List a -> a
head (Empty) = error " the empty list have no head"
head (Cons x xs) = x

在后一个示例中,
x
实际上是一个列表<代码>[x]
成为列表列表,例如
[[1,2],[3,4]]

(++)
希望两侧都有相同类型的列表。当您使用它时,您正在执行
[[a]]+[a]
,这就是编译器抱怨的原因。根据您的代码,
a
将与
[a]
的类型相同,这是不可能的

(x:xs)
中,
x
是列表的第一项(头部),而
xs
是除头部(即尾部)以外的所有内容。这里的名称不相关,您不妨称它们为
(head:tail)

如果您真的想获取输入列表的最后一项并将其放在结果列表的前面,您可以执行以下操作:

rotate :: [a] -> [a]
rotate [] = []
rotate lst = (last lst):(rotate $ init lst)
view :: [a] -> (a, [a])
view xs = (last xs, init xs)

someFunction :: [a] -> ...
someFunction (view -> (x,xs)) = ...

注意:我根本没有测试过这段代码,因为我目前没有可用的Haskell环境。

我也是Haskell的新手,所以我的答案并不权威。无论如何,我会使用
last
init

Prelude> last [1..10] : init [1..10]
[10,1,2,3,4,5,6,7,8,9]


按照你的建议倒车可能效率要低得多。最后一个不是O(1)运算,而是O(N),这意味着按照您的建议旋转将变成O(N^2)alghorhim

资料来源:

您的第一个版本具有O(n)复杂性。事实并非如此,因为ase++也是O(N)运算

你应该这样做

rotate l =  rev l []
   where
      rev []     a = a
      rev (x:xs) a = rev xs (x:a)

来源:

如果您愿意使用与普通列表不同的内容,您可以查看containers包中的
Seq
类型,如文档所示。这有O(1)个cons(前面的元素)和snoc(后面的元素),并允许通过使用视图从前面和后面对元素进行模式匹配。

“是否有(xs:x)(与元素连接的列表,即x是列表中的最后一个元素)这样我就可以将最后一个列表元素放在列表的前面?”

不,不是你的意思。函数定义左侧的这些“模式”反映了程序员如何定义数据结构并将其存储在内存中。Haskell的内置列表实现是一个从一开始就排序的单链接列表,因此函数定义可用的模式正好反映了这一点,公开了第一个元素加上列表的其余部分(或者,空列表)

对于以这种方式构造的列表,最后一个元素不能立即作为列表最顶端节点的存储组件之一使用。因此,该值不是出现在函数定义左侧的模式中,而是由右侧的函数体计算

当然,您可以定义新的数据结构,因此如果您想要一个新的列表,通过模式匹配使最后一个元素可用,您可以构建它。但也有一些代价:也许你只是将列表向后存储,这样它就成为了模式匹配无法使用的第一个元素,并且需要计算。可能您正在结构中存储第一个和最后一个值,这需要额外的存储空间和簿记


考虑一个数据结构概念的多个实现是完全合理的——向前看一点,这是Haskell的类/实例定义的一种用法。

简单的回答是:这在模式匹配中是不可能的,必须使用函数

很长的答案是:它不在标准Haskell中,但如果您愿意使用名为View Patterns的扩展,并且如果您对模式匹配没有问题,最终需要的时间比常量时间更长,则可以使用它

原因是模式匹配首先基于结构的构造方式。列表是一种抽象类型,具有以下结构:

data List a = Empty | Cons a (List a)
           deriving (Show) -- this is just so you can print the List 
当您声明这样一个类型时,您将生成三个对象:一个类型构造函数
List
,以及两个数据构造函数:
Empty
Cons
。类型构造函数接受类型并将其转换为其他类型,即,
List
接受类型
a
,并创建另一个类型
List a
。数据构造函数的工作方式类似于返回类型为
列表a
的函数。在这种情况下,您有:

Empty :: List a
表示空列表和

Cons :: a -> List a -> List a
它获取类型为
a
的值和一个列表,并将该值附加到列表的头部,返回另一个列表。因此,您可以按如下方式构建列表:

empty = Empty         -- similar to []
list1 = Cons 1 Empty  -- similar to 1:[] = [1]
list2 = Cons 2 list1  -- similar to 2:(1:[]) = 2:[1] = [2,1]
这或多或少是列表的工作方式,但是在
空的地方有
[]
,在
Cons的地方有
(:)
。当您键入类似于
[1,2,3]
的内容时,这只是
1:2:3:[]
cons1(cons2(cons3为空))
的语法糖

当您进行模式匹配时,您正在“反构造”类型。了解类型的结构可以让您对其进行独特的反汇编。考虑函数:

Occurs check: cannot construct the infinite type: a = [a]
When generalising the type(s) for `rotate'
head :: List a -> a
head (Empty) = error " the empty list have no head"
head (Cons x xs) = x
类型匹配的结果是数据构造函数与您给定的某种结构匹配。如果它与
Empty
匹配,则您的列表为空。如果If匹配
Const x xs
,则
x
必须具有类型
a
,并且必须是列表的头,并且
xs
必须具有类型
list a
并且是列表的尾,因为这是数据构造函数的类型:

Cons  :: a -> List a -> List a
如果
Cons x xs
属于
列表a
类型,则
x
必须是
a
xs
必须
view :: [a] -> (a, [a])
view xs = (last xs, init xs)

someFunction :: [a] -> ...
someFunction (view -> (x,xs)) = ...