我正在通过Paulson的 ML阅读工作程序员并对数据类型和结构之间的区别感到有点困惑。
在p。 142,他定义了二元树的类型如下:
datatype 'a tree = Lf
| Br of 'a * 'a tree * 'a tree;
这似乎是一个递归定义,其中' a表示某种固定类型。所以每当我看到它时,它必须始终引用相同的类型。
在p。 148,他讨论了二叉树的结构:
" ...我们一直在关注一个想象中的ML会话,我们在其中一次输入一个树函数。现在我们应该将这些函数中最重要的函数收集到一个名为 Tree 的结构中。我们必须这样做,因为我们的一个函数( size )与内置函数冲突。使用结构的一个原因是为了防止这种名称冲突。
但是,我们将 tree 的数据类型声明留在结构之外。如果它在里面,我们应该被强制通过 Tree.Lf 和 Tree.Br 来引用构造函数,这将使我们的模式不可读。因此,在续集中,想象一下我们做了以下声明:
datatype 'a tree = Lf
| Br of 'a * 'a tree * 'a tree;
structure Tree =
struct
fun size Lf = 0
| size (Br( v, t1, t2)) = 1 + size t1 + size t2;
fun depth...
etc...
end;
我有点困惑。
1)数据类型和结构之间有什么关系?
2)" struct"的作用是什么?在结构定义中?
3)稍后,Paulson讨论了字典作为二叉搜索树的结构。他做了以下事情:
structure Dict : DICTIONARY =
struct
type key = string;
type 'a t = (key * 'a) tree;
val empty = Lf;
<a bunch of functions for dictionaries>
这让我认为struct指定了Dict定义中涉及的不同原语或复合类型。
虽然这是一个非常模糊的定义。有人想澄清吗?
感谢您的帮助, bclayman
答案 0 :(得分:6)
结构是模块。 struct
和end
关键字之间的所有内容都构成了此模块的主体。同样,您可以将签名视为抽象模块 interface 的描述。将签名归为结构(如示例中的: DICTIONARY
语法)会将模块的 exports 限制为该签名中指定的内容(默认情况下,所有内容都可访问)。这允许您隐藏模块的实现细节。
然而,ML模块比这更丰富。它们可以任意嵌套。还有仿函数,它们有效地从模块到模块(如果需要,可以使用“参数化模块”)。总而言之,ML中的模块语言本身就形成了一个完整的功能语言,结构作为基本实体,基于它们的算符,以及描述这些模块“类型”的签名。这种小语言是所谓的核心语言之上的一层,普通的价值观和类型都存在于其中。
所以,回答你的个人问题:
1)数据类型和结构之间没有特定的关系。后者只使用前者。
2)struct
- end
只是一个用于分隔结构体的关键字对(C传统中的语言可能会使用花括号)。
3)如上所述,结构是基本模块。它可以包含(和导出)任意其他语言实体,包括其他模块。通过将定义分组在一起,并可能通过签名归属隐藏其中的一些,您可以表达命名空间和封装(特别是抽象数据类型)。
我还应该注意到,保尔森关于模块描述的书已经过时,因为它早于当前的语言版本。特别是,它没有描述如何通过模块表达抽象数据类型,而是介绍了近20年来没有人使用的过时的abstype
声明。在Harper的Programming in Standard ML中可以找到关于ML中模块化编程的更广泛和最新的介绍。
答案 1 :(得分:1)
在此示例中,数据类型'a tree
描述的是能够存储单个类型的任何值的二叉树(https://en.wikipedia.org/wiki/Binary_tree)。定义中的'a
是一种变体类型,无论何时使用不同类型的树,以后都会将其约束为具体类型。这允许您定义树的结构一次,然后在任何类型中使用它。
Tree结构与数据类型定义是分开的。它用于将函数组合在一起,对'a tree
数据类型进行操作。它现在被用作模块化代码的一种方法,正如它所指出的那样,它可以防止命名空间冲突。
struct
只是一个标识符关键字,让编译器知道结构定义的起始位置,而end
关键字用于让编译器知道定义的结束位置。
字典结构定义了一个字典(一个键 - &gt;值数据结构),它使用树作为内部数据结构。再一次,该结构是一组函数,将用于创建和操作字典。字典结构中的type
组成了构成字典的内部数据结构的类型。以下函数定义了您公开的公共接口,以允许客户端使用字典。