使用Haskell和类型生成递归列表-递归锚?

使用Haskell和类型生成递归列表-递归锚?,haskell,recursion,Haskell,Recursion,为了更好地理解Haskell,我想使用sum类型构建一些递归列表结构 这两种类型不相关,但在同一个文件中: data EList = EList {elem::Point, rest::EList} | Empty data ETree = ENode {val:: Int, left::ETree, right::ETree} | Empty 所以我得到了一个“多个'Empty'声明”错误。在阅读这篇文章时,我了解到“Empty”不是一个关键字(正如我在课堂上呈现此数据类型时所假设的那样)

为了更好地理解Haskell,我想使用sum类型构建一些递归列表结构

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

data EList = EList {elem::Point, rest::EList} | Empty
data ETree = ENode {val:: Int, left::ETree, right::ETree} | Empty
所以我得到了一个“多个'Empty'声明”错误。在阅读这篇文章时,我了解到“Empty”不是一个关键字(正如我在课堂上呈现此数据类型时所假设的那样)

如果我想在我的程序中使用这样的n个类型,我必须为空元素提供n个不同的名称,这似乎是不对的

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

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

x = Empty
x
的类型是什么?它可以是
EList
ETree
,但计算机无法知道您指的是哪一个。这就是为什么一般来说,您不能在给定的文件中多次声明相同的名称

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

data List = Cons Point List | Nil
data Tree = Node Int Tree Tree | Leaf
(旁白:在sum类型中声明记录字段通常不是一个好主意,因为这意味着提取器将是分部函数。)

另一种方法是将两个重叠的名称放在不同的文件中

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

为什么不直接调用第一个“空”——
Nil
和第二个
Leaf
?然后它会“感觉正确”。但最终你必须这样做-否则
Empty
可以用来构建树或列表-也许一些语言扩展可以帮助你-我想
AllowAmbiguousTypes
,但我不确定。另一个选择是-因为它们不相关-创建两个模块-MyList和MyTree-然后,因为每个模块都有名称空间,问题解决了,如果在一个文件中同时使用这两个文件,则必须进行合格的导入。看一看这个软件包,可以看到一个组织整齐的示例。这是一个正确的答案,但我不得不指出,如果语言需要类型声明来定义模糊的定义,那么计算机将能够处理
x=Empty
定义。Haskell已经对数字文本执行了此操作。所以这是语言强加的规则,而不是自然法则。@Luiscasilas我同意,事实上,有些语言在不同类型的名称重叠方面比Haskell更灵活;Haskell选择优先处理类型推断。不过,数字文字不是完全相同的东西;它们是多态的,类型为
Num n=>n
,因此使用Haskell的常规实例选择规则选择类型。