想象一下,你在用乐高积木搭建一个城堡。在开始搭建之前,你需要知道有哪些类型的积木块,比如长方形的、正方形的、三角形的等等。这些就像是TL语言中的“内置类型和聚合类型”。
然后,当你有了所有的积木块之后,你就可以开始搭建城堡了。你会按照一定的顺序和方式将这些积木块组合起来。在TL语言中,这个过程就像是“函数”或“功能性组合子”,它们告诉你如何将基本的积木块组合成更复杂的结构。
TL语言的程序就像是一份建造指南,分为两个主要部分:
1. 第一部分是列出所有你可以使用的积木块类型,就像是在说:“我们有长方形的积木块、正方形的积木块和三角形的积木块。”
2. 第二部分是告诉你如何使用这些积木块来搭建不同的结构,就像是在说:“首先,将两个长方形积木块放在一起,然后在上面放一个三角形积木块,这样你就搭建了一个屋顶。”
在TL语言中,你会用一些特殊的规则来定义这些积木块和搭建步骤,这些规则就是“组合子声明”。而且,你可以给这些步骤编号,就像是“步骤1”、“步骤2”这样,这样你就知道搭建的顺序了。
最后,"---functions---"这个关键字就像是在建造指南中划分“积木块列表”和“搭建步骤”的分隔线,告诉你第一部分是积木块的列表,第二部分是搭建的步骤。
1. 额外的类型声明: 如果你在定义了函数之后,还需要添加更多的类型声明,你可以使用一个特殊的关键字 "--types---" 来做到这一点。这就像在建造城堡的时候,你可能会突然想到还需要一些特殊形状的积木块,这时你可以拿出一张新的图纸,上面写着 "--types---",然后列出所有额外需要的积木块类型。
2. 在类型部分声明功能性组合子: 有时候,你可能想要声明一个函数,它的返回类型是以一个感叹号(!)开始的。在TL语言中,如果你在类型部分声明这样的函数,那么这个感叹号会自动被添加到函数的返回类型前面。这就像是你有一个特殊的积木块,它的形状非常独特,需要特别注意,所以你在它的名字前面加了一个感叹号来提醒自己。
3. 为组合子显式定义32位名称: 如果你想给一个组合子一个特定的名字,你可以在组合子的名字后面立即加上一个井号(#),然后跟上8个十六进制的数字。这就像是给积木块一个独一无二的编号,这样你和其他人就可以准确地知道需要哪个积木块。十六进制数字是0到9和A到F的数字系统,用于计算机编程中表示颜色、编码等。
举个例子,如果你有一个叫做“MyFunction”的函数,你想给它一个特定的32位名称,你可以这样写:
MyFunction#12345678
这里的“MyFunction”是你给函数起的名字,“#”表示你将要给它一个特定的名称,“12345678”是这个函数的十六进制编号。
总结一下,这段话讲的是如何在TL语言中处理额外的类型声明,以及如何给你的函数和组合子起名字或者编号,以便于在构建复杂结构时能够清晰地识别和使用它们。
1. 复合构造: 你可以使用形如 <namespace_identifier>.<constructor_identifier> 和 <namespace_identifier>.<Type_identifier> 的复合构造来作为构造函数或类型的标识符。这里的点( . )就像是文件系统中的目录分隔符,它把不同的部分分隔开来。
2. 命名空间: 点号前面的部分被称为“命名空间”。命名空间是一种逻辑上的分组,它允许你在同一个项目中有相同名字的类型或构造函数,只要它们在不同的命名空间中。
3. 命名规则: 在复合构造中,点号后面的部分需要遵循特定的命名规则:类型标识符的首字母应该是大写的,而构造函数标识符的首字母应该是小写的。例如, auth.Message 会被认为是一个类型,因为它的首字母是大写的;而 auth.std_message 会被认为是一个构造函数,因为它的首字母是小写的。
4. 命名空间的声明: 与某些编程语言不同,TL语言中的命名空间不需要特别的声明。你可以直接在你的类型或构造函数前面加上一个命名空间前缀,语言引擎会自动理解这是一个命名空间。
举个例子,假设你在做一个社交网络应用,你可以这样组织你的代码:
user.Profile :这可能是一个表示用户个人资料的类型。
user.createProfile :这可能是一个构造函数,用于创建 user.Profile 类型的新实例。
这里, user 是命名空间,它告诉我们 Profile 类型和 createProfile 构造函数都属于 user 这个逻辑分组。这样做的好处是,即使在其他部分的代码中也有叫做 Profile 的类型或 createProfile 的构造函数,只要它们不在 user 这个命名空间中,就不会影响到当前的代码。
// built-in types
int#a8509bda ? = Int;
long ? = Long;
double ? = Double;
string ? = String;
null = Null;
vector {t:Type} # [ t ] = Vector t;
coupleInt {alpha:Type} int alpha = CoupleInt<alpha>;
coupleStr {gamma:Type} string gamma = CoupleStr gamma;
/* The name of the type variable is irrelevant: "gamma" could be replaced with "alpha";
However, the combinator number will depend on the specific choice. */
intHash {alpha:Type} vector<coupleInt<alpha>> = IntHash<alpha>;
strHash {alpha:Type} (vector (coupleStr alpha)) = StrHash alpha;
intSortedHash {alpha:Type} intHash<alpha> = IntSortedHash<alpha>;
strSortedHash {alpha:Type} (strHash alpha) = StrSortedHash alpha;
// custom types
pair x:Object y:Object = Pair;
triple x:Object y:Object z:Object = Triple;
user#d23c81a3 id:int first_name:string last_name:string = User;
no_user#c67599d1 id:int = User;
group id:int title:string last_name:string = Group;
no_group = Group;
---functions---
// Maybe some built-in arithmetic functions; inverse quotes make "identifiers" out of arbitrary non-alphanumeric strings
`+` Int Int = Int;
`-` Int Int = Int;
`+` Double Double = Double;
// ...
// API functions (aka RPC functions)
getUser#b0f732d5 int = User;
getUsers#2d84d5f5 (Vector int) = Vector User;
1. 内置类型:
int#a8509bda ? = Int; :定义了一个名为 Int 的整数类型,并给它分配了一个特定的32位标识符 a8509bda 。这个标识符是可选的,因为如果不指定,TL语言会自动生成一个基于类型名称的标识符。
long ? = Long; :定义了一个名为 Long 的长整数类型,没有指定标识符,所以TL语言会默认生成一个。
double ? = Double; :定义了一个名为 Double 的双精度浮点数类型。
string ? = String; :定义了一个名为 String 的字符串类型。
null = Null; :定义了一个代表空值的 Null 类型。
2. 复合类型:
vector {t:Type} # [ t ] = Vector t; :定义了一个泛型向量(数组)类型 Vector ,它可以包含任何类型的元素。
coupleInt {alpha:Type} int alpha = CoupleInt<alpha>; :定义了一个名为 CoupleInt 的复合类型,它包含两个元素,第一个是整数类型,第二个是任意类型 alpha 。
coupleStr {gamma:Type} string gamma = CoupleStr gamma; :定义了一个名为 CoupleStr 的复合类型,它包含两个元素,第一个是字符串类型,第二个是任意类型 gamma 。注释中提到类型变量的名称不重要,但是组合子的编号会依赖于具体的选择。
3. 哈希表类型:
intHash {alpha:Type} vector<coupleInt<alpha>> = IntHash<alpha>; :定义了一个整数键哈希表类型 IntHash ,它的值是类型 alpha 。
strHash {alpha:Type} (vector (coupleStr alpha)) = StrHash alpha; :定义了一个字符串键哈希表类型 StrHash ,它的值是类型 alpha 。
intSortedHash {alpha:Type} intHash<alpha> = IntSortedHash<alpha>; :定义了一个有序的整数键哈希表类型 IntSortedHash 。
strSortedHash {alpha:Type} (strHash alpha) = StrSortedHash alpha; :定义了一个有序的字符串键哈希表类型 StrSortedHash 。
4. 自定义类型:
pair x:Object y:Object = Pair; :定义了一个包含两个对象的简单复合类型 Pair 。
triple x:Object y:Object z:Object = Triple; :定义了一个包含三个对象的复合类型 Triple 。
user#d23c81a3 id:int first_name:string last_name:string = User; :定义了一个用户类型 User ,并显式分配了一个标识符 d23c81a3 。这个标识符实际上是类型定义字符串的CRC32校验和,如果不指定,TL语言会自动使用这个值。
no_user#c67599d1 id:int = User; :定义了一个没有用户名和姓氏的用户类型 User ,并分配了一个标识符。
group id:int title:string last_name:string = Group; :定义了一个群组类型 Group 。
no_group = Group; :定义了一个没有标题和姓氏的群组类型 Group 。
5. 函数:
+ 和 - 操作符定义了整数和双精度浮点数的加法和减法函数。
getUser#b0f732d5 int = User; :定义了一个函数 getUser ,它接受一个整数参数并返回一个 User 类型的结果。
getUsers#2d84d5f5 (Vector int) = Vector User; :定义了一个函数 getUsers ,它接受一个整数向量作为参数并返回一个 User 类型的向量。
6. 向量类型:
vector#1cb5c415 {t:Type} # [ t ] = Vector t; :定义了一个泛型向量类型 Vector ,它可以包含任何类型的元素。这个类型有一个显式分配的标识符 1cb5c415 。
7. 构造函数编号:
当计算 getUsers 函数的构造函数编号时,会计算字符串 "getUsers Vector int = Vector User" 的CRC32校验和(去掉所有括号)。
8. 类型表示法:
表示法 T0<T1,T2,...,Tn> 是语法糖,表示 (T0 (T1) (T2) ... (Tn)) 。例如, Vector<User> 和 (Vector User) 是完全可互换的。
这段代码展示了如何在TL语言中定义复杂的类型系统和函数,以及如何使用命名空间和类型变量来创建灵活的数据结构。
1. 通用构造函数:
在TL语言中,不需要为不同类型的向量(如 Vector int 、 Vector User 、 Vector Object 等)创建特殊的构造函数。相反,你可以使用一个通用的构造函数来处理所有这些情况。这意味着,不管你的向量包含哪种类型的元素,你都可以使用同一个构造函数来创建它。
2. 向量类型的构造函数:
vector#1cb5c415 {t:Type} # [ t ] = Vector t; 这行代码定义了一个名为 Vector 的泛型向量类型。这里的 {t:Type} 表示 Vector 是一个泛型类型,它可以包含任何类型的元素(由 t 表示)。 # [ t ] 是这个类型的标识符,而 Vector t 表示这个向量的元素类型是 t 。
#1cb5c415 是这个通用构造函数的显式分配的32位标识符。这个标识符是可选的,因为如果不指定,TL语言会根据构造函数的定义自动生成一个。
3. 构造函数编号的计算:
当你定义一个函数,比如 getUsers ,它接受一个整数向量并返回一个用户向量( Vector int -> Vector User ),TL语言会自动计算这个函数的构造函数编号。
这个编号是通过计算字符串 "getUsers Vector int = Vector User" 的CRC32校验和得到的。在计算过程中,会去掉字符串中的所有括号。
4. 类型表示法:
TL语言提供了一种简洁的表示法 T0<T1,T2,...,Tn> ,这是 (T0 (T1) (T2) ... (Tn)) 的语法糖。这意味着你可以用 Vector<User> 来代替 (Vector User) ,这两种表示方法是完全等价的。
这种表示法使得定义和使用泛型类型更加方便和直观。
总结来说,这段话强调了在TL语言中,你可以使用通用的构造函数来处理不同类型的向量,并且TL语言提供了一种简洁的泛型类型表示法,使得定义和使用这些类型更加方便。此外,TL语言会自动为你的函数和类型生成唯一的标识符,除非你显式地指定一个。