使用Haskell和类型生成递归列表-递归锚?
为了更好地理解Haskell,我想使用sum类型构建一些递归列表结构 这两种类型不相关,但在同一个文件中:使用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”不是一个关键字(正如我在课堂上呈现此数据类型时所假设的那样)
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的常规实例选择规则选择类型。