基本概念
基本概念
值
单个数据称之为值。
值广义上分为:基础值和结构化值。
基础值是最基本的形式,结构化值是由基础值和其他结构化值构成的。
表达式
表达式是用于构造值的公式。
"hello world!"
123
1 + 2
[x = 1, y = 2]
let x = 1 in x + 1
error "error message"
最简单的表达式是表示值的字面。
表达式组合形成新的表达式。
1 + 2
1
和2
都是1+2
的子表达式,1+2
是1
和2
的父表达式。
执行表达式中使用的语法结构所定义的算法称为_评估_(evaluating)表达式。
环境和变量
表达式在一个给定的环境中运行。环境(environment)是一组被命名的值,这些值叫变量。每个变量在环境中都有一个唯一的名字,这个名字叫标识符(identifier)。
顶级(或叫根)表达式在全局环境中计算。全局环境由评估器(evaluator)提供,而不是根据表达式的内容来确定。全局环境包括标准库定义,并且可能会受到某些文档集的节导出的影响。
子表达式的计算环境由父表达式确定,大多数父表达式将在相同的环境中评估子表达式,但也有一些会使用不同的环境。全局环境是评估全局表达式的父环境。
下面的例子都假定在全局环境中计算。
[
x = 1, // 环境:y, z
y = 2, // 环境:x, z
z = x + y // 环境:x, y
]
let表达式和记录初始化表达式表现一样。
let
x = 1, // 环境:y, z
y = 2, // 环境:x, z
z = x + y // 环境:x, y
in
z // 环境:x, y, z
子环境会包含父环境,如果不同层级中存在相同名称的标识符,则会按照就近原则(即以离表达式最近的环境中的标识符为准)。
[
a =
[
b = b + 10, // 环境:z, a, 外部b
a = 2, // 环境:b, z
z = b // 环境:b, a
],
b = 3 // 环境:a
]
环境规则:
- 环境是指当前可引用值的标识符的集合。
- 标准库可以在有效表达式的任意位置使用,因为其位于全局环境。
- 子环境包含父环境中的内容,如果存在相同的标识符,以最近的为准。
- 当前表达式的环境中,不包含正在初始化的值的标识符。如果需要访问正在初始化的标识符,可以使用
@
操作符。
标识符引用
identifier-reference表示引用环境中的变量(标识符)。
identifier-expression:
identifier-reference
identifier-reference:
exclusive-identifier-reference
inclusive-identifier-reference
exclusive-identifier-reference:
identifier
inclusive-identifier-reference:
@
identifier
用于获取当前环境中(包含父环境)正在初始化的标识符。如果当前环境中不存在正在初始化的标识符,则该操作符将被忽略。
利用操作符可以得到递归的值,如递归函数、列表、记录等。
需要注意的是:由于惰性计算,理论上可以无限的向下访问。
let
f = (n)=>
if n = 1 then 1 else n * @f(n - 1)
in
f
let
f = {0, @f}
in
f{1}
let
f =
[
a = 1,
b = @f
]
in
f[b]
评估顺序
因为环境中包含当前环境及父环境中的所有可用标识符,所以,被用到的标识符并非一定要先定义。
[
c = a + b,
a = 1,
b = 2
][c]
对于评估器而言,c=a+b
依赖a
和b
,但是需要注意:a
和b
的计算顺序并非是确定的,可以是先a
,也可以是后a
,也可以是同时(并行)计算a
和b
。
副作用
如果表达式没有明显的依赖项,表达式评估器会自动计算顺序,也就是说,表达式的计算顺序可能是不确定的。
不可变性
某个值被计算后就是不可变(immutable)的,这意味着无法再对其进行修改。
不可变性的例外是列表和表,它们具有流式语义(streaming semantics)。也就是说如果重复枚举列表的项或表的行可能会出现不同的结果。流式语义能够构建M表达式来转换无法立即放入内存的数据集。
函数值虽然本身具有不可变性,但是不同情况下的输出可以不同,因此也会出现不确定性。比如:当前时间、数据库的实时状态。
let
f = List.Transform({1..5}, each Number.Random())
in
{f{0}, f{0}}
不确定性也可能来自于错误,错误发生时会停止计算(除非使用try表达式进行处理)。如果忽略并行计算,首先计算的表达式出现错误,则整个表达式将会中止,从而确定哪个先被计算。