理解Haskell中的数据结构

理解Haskell中的数据结构,haskell,Haskell,我的家庭作业有问题(主题是:“函数数据结构”)。 请理解我不想让任何人帮我解决家庭作业。 我只是在理解这个结构时遇到了一个问题: data Heap e t = Heap { empty :: t e, insert :: e -> t e -> t e, findMin :: t e -> Maybe e, deleteMin :: t e -> Maybe (t e), merge :: t e -> t e -> t e, contains

我的家庭作业有问题(主题是:“函数数据结构”)。 请理解我不想让任何人帮我解决家庭作业。 我只是在理解这个结构时遇到了一个问题:

data Heap e t = Heap {
 empty :: t e,
 insert :: e -> t e -> t e,
 findMin :: t e -> Maybe e,
 deleteMin :: t e -> Maybe (t e),
 merge :: t e -> t e -> t e,
 contains :: e -> t e -> Maybe Int
}
据我所知,“empty”、“insert”等函数可以应用于“Heap”类型的数据。 现在我只想了解“堆”是什么样子。 所以我输入了如下内容:

  a = Heap 42 42
但我也有一些错误,我真的无法处理

也许这是一个愚蠢的问题,我只是无缘无故地停留在这一点上,但它正在杀死我。
感谢所有帮助

堆是一个包含六个元素的记录。为了创建该类型的值,必须提供所有六个元素。假设您有适当的值和函数,您可以创建如下值:

myHeap = Heap myEmpty myInsert myFindMin myDeleteMin myMerge myContains

然而,这看起来不像是惯用的Haskell设计。为什么不定义独立于数据的泛型函数,或者如果它们必须捆绑在一起,定义一个typeclass呢?

如果您真的想了解该类型,您需要先了解一些必要条件

类型和值(以及函数) 首先,您需要了解什么是类型和值。我假设你明白这一点。例如,您理解
“hello”
作为一个值和它的类型之间的分隔,
String
,并且您清楚地理解我说
a=“hello”::String
和:

a :: String
a = "hello"
如果您不了解这一点,那么您需要研究Haskell中的值和类型。这里有很多书可以帮助你,比如我帮助撰写的这本书:

我还将假设您了解什么是函数和咖喱,以及如何使用它们

多态类型的 其次,由于您的示例包含类型变量,您需要了解它们是什么。也就是说,你需要了解什么是多菌型。因此,例如,
可能是a
,或者
可能是b
,您需要了解
可能是String
可能是Int
有什么不同,什么是
Num a=>[a]
甚至像
Num a=>[可能是a]
这样的东西

同样,有很多免费或付费的书可以帮助你,上面的例子也包括了这一点

代数数据类型
接下来是代数数据类型。这是Haskell拥有的一个非常酷的特性。像Elm和Idris这样类似Haskell的语言以及其他类似Rust的语言也有这种语言。它允许您定义自己的数据类型。这些不仅仅是像其他语言中的结构,是的,它们甚至可以包含函数

可能实际上是代数数据类型的一个示例。如果您了解这些,您将知道:

data Direction = North | South | East | West
定义一个名为
Direction
的数据类型,其值只能是
North
South
East
West
中的一个,并且您还可以使用上面的polymorhpic类型变量来参数化您的类型,如下所示:

data Tree a = EmptyNode | Node (Tree a) (Tree a)
它既使用可选性(如上面的
方向
的和类型)又使用参数化

除此之外,每个值中还可以有多个类型。这些类型称为乘积类型,Haskell的代数数据类型可以表示为可以包含乘积类型的和类型的组合。例如:

type Location = (Float, Float)
data ShapeNode = StringNode Location String | CircleNode Location Float | SquareNode Location Float Float
也就是说,每个值可以是
StringNode
CircleNode
SquareNode
中的一个,并且在每种情况下,每个值都有一组不同的字段。例如,要创建
StringNode
,您需要像这样传递it构造函数的值:
StringNode(10.0,5.3)“字符串”

同样,免费提供的书籍将更详细地介绍这些内容,但我们现在正在朝着对Haskell有更多基本了解的方向前进

最后,为了充分理解您的示例,您需要了解

记录类型 记录类型与上面的产品类型相同,只是字段被标记而不是匿名。因此,可以这样定义形状节点数据类型:

type Location = (Float, Float)

data ShapeNode
  = StringNode { stringLocation :: Location, stringData :: String }
  | CircleNode { circleLocation :: Location, radius :: Float }
  | SquareNode { squareLocation :: Location, length :: Float, height :: Float }
每个字段都已命名,不能在数据值中重复相同的名称

除此之外,要理解上述示例,您还需要意识到您的示例包含所有这些内容,以及您拥有的数据类型中的函数作为记录字段值这一事实


彻底充实自己的理解是一个好主意,不要跳过任何步骤,这样将来你就能更容易地理解这些事情了。:)祝你好运

Heap et
看起来不是一种表示堆的类型,而是一种表示堆实现的类型。也就是说,它是一组在堆上操作的函数,或者更确切地说,是在一些通用容器上操作的函数。@chi-oh好的,我现在知道了。这并不难:这个答案太棒了!谢谢你抽出时间:)这有助于洗液我真的很高兴。这是我开始时希望得到的答案。帮助别人的人往往会跳过一些东西,漏掉一些东西,或者做一些随意的解释。这是可以理解的,但帮助不大。我上面概述的四个主题中的每一个都是值得彻底学习的完整主题,但是初学者没有办法知道他们遗漏了什么,除非有人告诉他们。我坚信初学者需要阅读比大多数资源所允许的更多的内容。话虽如此,现在已经有一些很棒的书了。“这是Haskell和其他一些纯函数式语言(如Elm、Idris和其他语言)的一个非常令人惊讶的酷特性。”请注意,但这并不局限于纯函数式语言,而且考虑到锈迹,我想说它根本不仅仅是函数式语言。@AlexeyRomanov当然。我不是说哪种语言没有这个功能,我是sa