2016-02-12 144 views
1

为了更好地理解Haskell,我想使用sum类型来构建一些递归列表结构。使用Haskell sum类型进行递归列表 - 递归锚?

这两种类型是不相关的,但在同一个文件:

​​

所以我得到一个错误“‘空’的多次声明”。阅读this后,我知道'空'不是一个关键字(正如我在这个数据类型在课堂上呈现时所假定的那样)。

如果我想在我的程序中使用n这样的类型,我必须为空元素提出n个不同的名称,这看起来不正确。

是否有一个共同的表达式来确定列表的结尾? 或者我应该不使用这种'自制'类型?

+0

你为什么不直接叫第一个'Empty' - 'Nil'和第二个'Leaf'?那么它会'感觉不错'。但最终你必须 - 做到这一点 - 否则'空'可以用来构建树或列表 - 也许一些LANGUAGE扩展可以帮助你 - 我想'AllowAmbiguousTypes',但我不知道。 – epsilonhalbe

+5

另一个选择是 - 因为它们不相关 - 创建两个模块 - MyList和MyTree - 然后,因为命名空间是每个模块,问题就解决了,如果您在一个文件中同时使用了两个模块,则必须执行限定的导入。看一看['containers'](https://hackage.haskell.org/package/containers)包,看看整齐排列的示例。 – epsilonhalbe

回答

2

假设您已被允许使用Empty构造函数声明两个数据类型,就像您所做的那样。鉴于定义

x = Empty 

什么是x的类型?它可能是EListETree,但电脑无法知道你的意思。这就是为什么一般来说,你不能在给定文件中多次声明相同名称的原因。

一个简单的解决方案就是简单地使用不同的名称。在这里,我使用Nil作为空白列表,Leaf作为空白树。

data List = Cons Point List | Nil 
data Tree = Node Int Tree Tree | Leaf 

(旁白:它通常不申报的总和类型记录的字段是个好主意,因为这意味着提取将部分功能。)

另一种方法是把你的两个重叠的名字在不同的文件。

List.hs:

module List where 
data List = Cons Point List | Empty 

Tree.hs:

module Tree where 
data Tree = Node Int Tree Tree | Empty 

现在,如果导入这两个模块,指的是Empty不允许的,因为再一次机器不知道哪一个你的意思。但是这一次,你可以使用合格的名字自行排序。

import List 
import Tree 

emptyList = List.Empty 
emptyTree = Tree.Empty 
+0

这是一个正确的答案,但我不禁要指出,如果语言需要像这样的含糊定义的类型声明,那么计算机将能够处理'x = Empty'定义。 Haskell已经为数字文字做了这个。所以这是一种语言规定的规则,而不是一些自然规律。 –

+0

@LuisCasillas我同意,事实上有些语言比Haskell更加灵活地处理不同类型的重叠名称; Haskell选择优先化类型推断。尽管如此,数字文字并不是完全相同的东西;它们是多态的,具有'Num n => n'类型,所以类型是使用Haskell的常规实例选择规则选择的。 –