数据构造函数中的奇怪类型语法

时间:2018-05-18 15:54:51

标签: haskell

我找到了一些代码

data Tree c a = Node String [Tree c a]
              | NodeWithCleanup c [Tree c a]
              | Leaf a

我不明白为什么有必要添加[Tree c a]。我不知道这个语法,你能解释一下吗?

4 个答案:

答案 0 :(得分:5)

列表类型[]

在Haskell列表(概念上是链接列表)中,类型为[]。列表只能包含一个类型的元素(因此列表不能同时包含IntString

如果列表因此包含a类型的元素,那么我们将其表示为[a]。例如,Int的列表表示为[Int]

  

注意:这种语法实际上是语法糖。如果你写下[a],在窗帘后面你实际上写了[] a

类型(带类型参数)

在你引用的代码片段中,程序员定义了一个类型Tree,该类型有两个类型参数c(“清理”的类型)和a( “叶子”的类型。这意味着类型Tree c a是一种类型,其中c是清理类型,a是叶类型。

如果我们想要构建此类Tree的列表,我们会写[] (Tree c a)或更方便的[Tree c a]

数据构造函数(带参数)

程序员已经定义了三个数据构造函数。数据构造函数可以看作是附加到对象的标签,它们将“参数”绑定在一起。数据构造函数具有的参数数量以及类型可能会有所不同。

在您的代码片段中有三个数据构造函数:

  1. Node一个带有两个参数的数据构造函数:StringTree c a s列表(其子项);
  2. NodeWithCleanup一个带有两个参数的dataconstructor:一个c(清理)和一个Tree c a s列表(其子项);和
  3. Leaf具有单个参数的数据构造函数:它存储的数据(类型a)。

答案 1 :(得分:3)

与Haskell中的大多数“语法”一样,这些[]根本不是特殊的语法。构造函数声明只列出要包含的类型。如果你添加唱片标签可能会更清楚:(我会在这里指出“清理”部分)

data Tree a
   = Node { nodeCaption :: String
          , subtrees :: [Tree c a] }
   | Leaf { leafContent :: a }

这基本上就像两个Python类:

class TreeNode:
  def __init__(self, caption, subs):
      self.nodeCaption = caption
      self.subtrees = subs
class TreeLeaf:
  def __init__(self, content):
      self.leafContent = content

......打算像

一样构建
TreeNode("foo", [TreeNode("bar1", TreeLeaf(1)), TreeNode("bar2", TreeLeaf(2))])

在Haskell实现中,您只需编写

Node "foo" [Node "bar1" (Leaf 1), Node "bar2" (Leaf2)]

为此。

方括号特殊语法,因为它们是为列表保留的,但无论你是否用它们编写它们,都是这样做的函数的类型签名或数据声明。

答案 2 :(得分:2)

在定义值构造函数K时,符号K T1 T2 .. Tn表示K是一个构造函数,它采用n个值,第一个是类型T1等等。

Node String [Tree c a]中,我们可以看到Node有两个参数。第一个是字符串(String)。第二个是树的列表([Tree c a])。因此,节点包括字符串和子树列表。

相反,NodeWithCleanup c [Tree c a]表示带清理节点包含类型c的值和子树列表。

Leaf a表示叶子包含a类型的单个值。

答案 3 :(得分:0)

这不是语法问题;这是一个语义问题。 Leaf值只包含a类型的值。另外两个构造函数包含Tree值的列表,使其成为递归数据结构。 Tree c a可以是叶节点(例如Leaf 3),也可以是具有任意子树数的内部节点(例如Node "foo" [Leaf 1, Leaf 3, (Node "bar" []])。