枫叶/深入了解枫叶
枫叶有三个主要组件:用户界面、内核和库。
最近的枫叶版本包含三个用户界面可执行文件(对于大多数操作系统),两个图形用户界面(GUI):标准 GUI 和经典 GUI,以及一个命令行(基于字符)界面。
标准 GUI 是一个 Java 应用程序,而经典 GUI 是一个本地应用程序。
内核(解释器)处理枫叶的基本功能(例如基本数据结构、输入/输出、整数和有理数运算、简单的多项式计算和基本化简)。它是用 C 和 C++ 编写的。在启动枫叶会话时,它会被完整加载。
库包含系统的大多数例程。它是用枫叶高级编程语言编写的。这是一种解释型语言。它不会被编译。它的例程存储在 .mla 档案中。根据需要将库例程加载到系统中。这种设计的模块化允许用户消耗与实际使用的代数功能成比例的计算机资源。
一些数值也用 C 和 C++ 实现,并通过枫叶的外部调用机制由库例程动态访问。
除了内置函数外,每个例程的枫叶源代码都可以显示。
枫叶有一个全面的在线帮助设施。
对用户来说,枫叶就像一个“交互式计算器”。
枫叶系统的输入由一系列语句组成,语句之间用语句分隔符(分号 ; 和冒号 :)分隔。系统以交互模式运行,在输入时执行语句。
主程序读取输入,调用解析器,然后为遇到的每个完整语句调用语句求值器。
枫叶中有八种类型的语句:赋值语句、表达式、读取语句、保存语句、选择语句、重复语句、空语句和退出语句。
枫叶将读取无限数量的语句;它的正常结束是通过退出语句的求值(而不是解析)实现的。
解析器和一些基本内部函数负责构建枫叶内部使用的所有数据结构。
枫叶语言被设计为交互式使用。
一个统一的观点是,枫叶中的所有变量都是编程变量。那些用作数学符号的变量,其值为它们自己的名称;那些用作编程变量的变量,其值为分配给它们的其它东西。
枫叶字符集包含字母、数字和特殊字符。
标记由关键字、编程语言运算符、字符串、自然整数和标点符号组成。
数字、字符串和名称是枫叶中最简单的对象。
自然整数是任何一个或多个数字的序列。枫叶中的数字常量(整数、有理数和浮点数)是由自然整数使用编程语言运算符形成的。自然整数的长度,因此整数、有理数和浮点数的长度是任意的(即,长度限制是系统相关的,但通常远大于用户会遇到的长度)。
名称是可以分配值的字符序列,因此它表示变量。任何表达式都可以分配给名称。如果未将值分配给名称,则它代表它自身。
名称的最简单形式是字母(a-z,A-Z)后跟零个或多个字母、数字(0-9)和下划线(_)。即,枫叶区分大小写字母。因此,名称 pvar、Pvar、PVAR、pVaR 都引用不同的变量。名称的最大长度是系统相关的。在 32 位平台上,它是 524,271 个字符;在 64 位平台上,它是 34,359,738,335 个字符。在 16 位平台上是 499 个字符?
名称的另一种形式是下划线后跟零个或多个字母、数字和下划线。这种名称由枫叶用作全局变量名称,实际上保留供库代码使用。例外的是以 _Env 开头的名称,它们被认为是环境变量。
一些其他名称已由枫叶定义,要么作为关键字(例如 if、then、else、do、quit),要么作为命令名称(例如 sin、cos、ln、diff、int),环境变量(例如 Digits、UseHardwareFloats、printlevel、Rounding),要么作为预定义的数学常量(例如 Pi、I、GAMMA)。
因此,用户应避免使用这些名称。
名称也可以通过将任何字符序列括在反引号字符对(左单引号)(` `)中来形成。例如
>`This is a name`;
字符串是具有固定值的字符序列(它不能分配任何其他值)。字符串的最大长度是系统相关的。在 32 位平台上,它是 268,435,439 个字符;在 64 位平台上,它是 34,359,738,335 个字符。
字符串通过将任何字符序列括在双引号字符对(" ")中来编写。例如
>"This is a string";
表达式是枫叶语言中的基本实体。
每个枫叶表达式都保存在一个数据结构中。
集合是表达式的无序集合。任何有效的枫叶表达式都可以包含在集合中。
枫叶中的每个对象都与它相关联的类型。
类型由计算的域或子域定义。
枫叶中未赋值的名称,由于没有声明,可以代表任何数据类型。
在枫叶中,类型是任何由 type 函数识别的表达式,它会导致 type 函数从一些表达式集中返回 true,否则返回 false。
类型可以是简单类型或结构化类型。它们可以在枫叶中预定义,也可以由用户定义。简单类型是由单个名称标识的,而结构化类型可以由简单类型或其他结构化类型组成。结构化类型也可以递归地定义。
请记住,虽然你总是可以查询对象的类型,但在枫叶中没有办法规定某个变量始终为某种类型。
一般来说,枫叶试图保留数据的类型。
枫叶中对象的类型(通常与对象实际上是什么样的数据结构有关)和属性(与对象可以代表的数学对象有关)之间存在根本区别。
类型和属性之间有区别。*对象* *具有*与其本质相关的类型——它不能被赋予或“分配”或声明为某种类型。
名称或符号可以被赋予属性。一些比符号更复杂的物体也可以被赋予这样的属性。许多属性的名称与类型相同。“float”是一个属性和一个类型。符号永远不可能是 float、integer 等类型的,但它可以被赋予该属性。
编程语言的运算符有三种类型:二元运算符、一元运算符和零元运算符。
连接符或|| 运算符(以前称为点运算符)是 Maple 中的命名运算符——它生成全局名称。
ditto 运算符% 用于回调最后一个结果,它在过程内部是局部的,但 Maple 会完全对其进行评估。
@ 是函数组合运算符。
@@ 是重复函数组合运算符
在 Maple 中,语句通常在当前环境中尽可能远地进行评估。
在 Maple 中,表达式的评估通常是在完全的递归评估模式下执行的。
无论是在过程内还是在交互式级别,Maple 始终对全局变量应用相同的评估规则。它会完全评估所有全局名称,除非 (*) 此类变量的 (*) 值是表格或过程,在这种情况下,Maple 会在赋值链中的最后一个名称处停止评估。此评估规则称为最后名称评估。
(*) 全部评估 (*)
完全评估规则的主要例外情况是特殊数据结构(如表格、矩阵和过程)以及过程内部局部变量的行为。
简而言之,将表达式括在反引号中会延迟对该表达式进行评估,使其在 Maple 解析器中循环一次。
引用表达式会延迟评估,但不会阻止自动简化和算术运算。
连接通常遵循完全评估规则,但最左侧的符号不会被评估。
Maple 中布尔表达式的评估使用三值逻辑。
在 Maple 中,内存中每个对象的实例只有一个。
在内部,Maple 将每个对象分解成逻辑子对象,然后再次分解成更小的子对象,直到到达基本元素。
Maple 中的每个表达式都在内部由一个表达式树表示,其中每个节点都是一种特定数据类型。
Maple 中的每个结构都由各个部分或操作数组成,这些部分或操作数通过各种运算符串在一起。
表达式的结构可以模拟成一棵树。这些树模型也被称为“有向无环图”或 DAG。
Maple 的整体性能部分得益于使用基于表格的算法来执行关键功能。表格在 Maple 内核中用于评估和简化,以及不太重要的功能。为了简化,Maple 在整个会话中保留每个表达式或子表达式的单个副本。
迄今为止,Maple 内核维护的最重要的表格是简化表格。此表格的主要目的是确保简化的表达式在内存中具有唯一的实例。每个输入到 Maple 或内部生成的表达式都会与简化表格进行比较,如果找到,则会丢弃新表达式并使用旧表达式。
每个表达式都使用其签名作为键输入到简化表格中。表达式的签名本身就是一个哈希函数,它具有一个非常重要的属性:等效表达式的签名相等。如果两个表达式不同,那么它们在简化基本级别上不可能相等。
如果找到签名,则会执行完整的比较以验证它是否为相同的表达式。
此外,由于在垃圾回收期间保留了活动对象的相对顺序,这意味着对象序列可以通过机器地址进行排序。
可以使用快速加载的内部格式将 Maple 对象存储在顺序文件中。
数组和表格使用 Maple 的内部哈希表实现。因此,稀疏数组与密集数组一样高效。
Maple 中的包是与相关函数的集合,这些函数存储在 Maple 库中。
包实际上是一个函数表格,表格查找语法直接调用包中的过程。
包只是一个表格,其中条目是过程,索引是过程名称的“简写”。
Maple 中的包的概念允许用户使用一个 Maple 命令(即 with 命令)定义一整套新函数。
Maple 包加载速度非常快,因为实际上,加载包只需要定义库中新函数的位置。没有加载任何代码,但包的每个成员函数都成为 readlib 定义的。(更新)
要构建一个 Maple 包,请从模块开始,使用选项包
modu:=module();
option package; ........... ........... .............. end module;
type(modu, package);
true