“一切皆表达式”
Everything is an expression.
是的,理解了上面这句话,就基本理解了Wolfram语言。至于其它的,那都是细枝末节。
当然,想要理解这句话,首先要明白Wolfram语言里的表达式是什么。典型地,f[x,y]
就是一个表达式,它由一个头部 f
,以及两个项 x
和 y
构成。通常,我们会用 f[x,y]
来表示一个函数 ,但同时,这种形式也代表了Wolfram语言里表达式的一般结构。
一般的,表达式由头部和项组成,而头部和项同样也是表达式。这种结构不仅可以用来表示函数,它也可以用来表示列表、图形、动态控件,甚至是笔记本。表达式的这种灵活性为Wolfram语言语法的高度一致性,在理解了这种一致性的基础上,再去看Wolfram语言的各种行为,就会变得好理解很多。
再举几个例子(通过FullForm
可以获得一个表达式的完整形式):
-
算术表达式
-
列表
-
图形
-
非符号头部的表达式
-
-
笔记本对象(输出仅供参考)
对象是结构化的表达式
前面提到了Wolfram语言表达式的一般结构,即:一个表达式由头部和若干项构成,而头部和项同样也是表达式,直到某个不可再分的原子对象,比如数字、字符串和符号。在最初的例子里,f[x,y]
中,头部f
,项x
,y
都是符号。而对于更复杂的表达式,往往有较深的层次和较多的子项,但如果掌握了一些方法(比如 善用 TreeForm
),分析一个表达式的结构并不困难。
理解了表达式的结构,以及Wolfram语言的这种一致性,那么Wolfram语言的很多设计与行为就好理解了。
比如,列表的下标为何从1开始?因为本质上,运算符[[...]]
提供的是按索引获取表达式各个项的一般方法,而作为语言一致性的表现,[[0]]
获取的是表达式的头部。因此,对任何列表,获取“下标”为0的部分得到的结果都会是List
。同样,像1[[0]]
这种在别的语言的使用者眼里看起来莫名奇妙的表达式,在Wolfram语言中是完全正确的(当然,我们推荐使用语义更清晰的Head[1]
进行表达)。事实上,不仅仅是[[...]]
,有相当一部分的列表操作可以以完全一致的行为用在任何表达式上,例如Length
、Cases
、Sort
、Map
……掌握好这些函数,在面对很多问题的时候都会有所帮助。
而表达式的这种结构特性使得它可以承载并组织各种各样的信息。自然而然地,我们可以使用表达式来表示对象。
作为展示“对象是结构化的表达式”的例子,再来看一个有趣的小trick:
上面这个例子实际展示了Plot
函数在绘图时是如何进行抽样的。而方法也很简单,只是把图中的线段替换为点。而这种操作之所以可行,也是表达式一致性的体现。在这里,函数Plot
输出的图形实际是一个Graphics
对象,从构成上看,无非就是包含一些图形基元和图形指令的Graphics
表达式,只要将连接点的Line
替换为不连接的Point
就可以显示出那些抽样点了。
小结
“一切皆表达式”是Wolfram语言语法的核心。Wolfram语言用表达式来表示算式、数据、图形、控件等等。而掌握了表达式的结构,对Wolfram语言里的各种对象、操作都会有更清晰准确地认识。在下篇里,将会讲到Wolfram语言中表达式的另一个重点——表达式的计算,以及我们如何控制计算。