Mathematica/初级操作

维基教科书,自由的教学读本

引言[编辑]

在这一章我们介绍基本的变量操作(如赋值),还有一些过程控结构(如条件和循环)。

符号和变量[编辑]

在Mathematica里,变量其实就是一些能储存定义的符号。更精确的说,变量就是不含模式的全局规则的左值(这是我们对变量的定义,下面会详细介绍)。

合法的符号名称[编辑]

一个合法的符号名称必须满足一下几个要求:

  • 不以数字开头(可以包含数字)
  • 不能使用特殊字符(@,#,$,%,^,&,*,!,~,`等等)
  • 不能使用下划线"_"
  • 可以使用希腊字母,甚至汉字

注:Mathematica是对大小写敏感的,<function>和<Function>被区别对待。 如果不是很清楚一个符号名是否是合法的可以用下面的方法判断:

Head[Unevaluated[你的符号名]]

如果得到的结果是Symbol,那么这个符号名就是合法的[1]。 另外提到一点,在定义符号的时候最好使用小写字母开头(以大写字母开头是完全可以的),因为所有的内置符号都是以大写字母开头的。使用小写字母开头的符号名可以一劳永逸的消除“撞车”的情况。

直接变量和OwnValues[编辑]

直接变量("Proper" variables)[2]就是一类直接用来储存表达式的符号。被存储的这个表达式的类型没有任何限制,可以是原子也可以是普通表达式。(实际上,Mathematica里根本就没有类型的概念) 接下来介绍函数OwnValues,这个函数用来查看直接变量被赋的值。比如:

In[]:=  a = 3;
        OwnValues[a]
Out[]=  {HoldPattern[a]:>3}

这里的等于号表示的是赋值操作符,下面会详细介绍。

这里我们就有了“直接变量”的另一种定义,即它们的值是存储在OwnValues里的。一个符号的OwnValues只能存储0个或1个规则,而且这里所存储的规则必须是直接和符号(拥有头部Symbol的表达式)挂钩的,这就是称这种变量为“直接变量”的原因。

索引变量和DownValues[编辑]

除了上面的方法,还有另外一种存值的方法,这种方法有时候也被当作某种形式的变量看待。下面是个具体的例子:

b[1] = 1;
b[2] = 4;
b[3] = 9;

这看起来很像是索引,其实不是的,真正的索引操作符是[[ ]]。我们可以来检查一下这里的定义是否存储在OwnValues里:

In[]:=  OwnValues[b]
Out[]=  {}

嗯,看起来没有。其实,上面的赋值过程所建立的规则被存储在DownValues(另一种全局规则)里:

DownValues[b]
{HoldPattern[b[1]]:>1,HoldPattern[b[2]]:>4, HoldPattern[b[3]]:>9}

可以看到,在同一个符号<b>的身上,被联系了好多条规则,都存储在<b>的DownValues里。所以,一种解释我们上面赋值过程的说法是:我们定义了一个函数<b>,这个函数的参数是三个明确的值1、2、3;然而,有时把b[n]看成是一种“索引变量”似乎更加方便。因为这里对b的定义没有用到模式,只是类似于索引的三个数字而已。

索引变量在某些情况下是很有用的。这里的“索引”还可以扩展为其它的类型,比如字符串,这样实现类似于Python里的“字典”的数据结构就成为可能。在Mathematica内部,哈希表被用来保证索引变量访问时的高效率。所以,虽然Mathematica没有直接提供哈希表的支持,仍然可以通过一些变相的方法(比如这里的索引变量)来使用内部的哈希表。

复合变量和SubValues[编辑]

基本不会用到,暂不译。

变量的清除[编辑]

被绑定在变量和函数上的规则都存储在全局规则库里,一个“清除”命令就显得十分重要了。这个可以通过Clear命令实现。Clear命令的作用是清除一个符号的所有定义,包括OwnValues、DownValues、SubValues等等。在使用一个符号之前清除它的定义是个好习惯。下面会给出许多例子,先来个简单的。

可以用<?>来查看当前<b>的定义:

?b
Global`b
b[1] = 1
b[2] = 4
b[2] = 9

现在执行Clear[b]:

Clear[b];
?b
Global`b

可以看到所有的定义都被清除了,但是符号<b>仍然存在于符号表(symbol table)里。

在这里需要注意的是,被Clear的对象只能是符号或者字符串[3]。下面尝试就失败了:

Clear[a[b]]
Clear::ssym: a[b] is not a symbol or a string.>>

在这种情况下,可以使用Unset(简写成=.)来清除特定的值。可以理解为给一个对象赋<.>就能把它的值清除了。具体用法详见帮助。

Clear命令能清除一个与一个符号绑定的所有规则,但是还有一些其它的性质是不能被清除的,比如选项(Options)和属性(Attributes)。看看下面的代码:

Options[b] = {Heads -> True};
Attributes[b] = HoldAll;

我们已经给<b>赋了一些性质,现在我们Clear一下:

Clear[b]
?b
Global`b
Attributes[b] = {HoldAll}
Options[b] = {Heads->True}

刚才赋的选项和属性都还在,要清除这些东西,可以用更厉害的ClearAll:

ClearAll[b];
?b
Global`b

不过,ClearAll还不是终极Boss,被ClearAll的符号还是没有完全消失(仍然在符号表内)。如果想把一个符号完全抹去,你需要Remove命令:

Remove[b];
?b
Information::notfound : Symbol b not found.>>

检测一个符号是否有值 ValueQ[编辑]

不同于其它语言,在Mathematica里,没有值的变量(就是一个无意义的符号)是完全合法的,为了检查一个变量是否有值,可以使用函数ValueQ。[4]

小结[编辑]

  • Mathematica中的变量可以是符号也可以是普通表达式,能用来存储任意的Mathematica表达式。
  • 符号名称可以包含字母或数字,但是不能以数字开头或包含特定的特殊符号,包括下划线。
  • 可以用Head[Unevaluated[符号名]]来检查一个符号名是否合法。
  • 符号名不得与内置符号相冲突,使用小写字母打头的符号名可以避免冲突。
  • <?>和<Information>可以用来查阅一个符号的信息。
  • 变量是用全局规则实现的。直接变量用OwnValues实现,索引变量用DownValues实现。
  • Clear用来清除变量上的规则;ClearAll在清除规则的同时清除选项和属性;Remove可以彻底清除一个符号;Unset用来清除一条特定的规则。

动态数据类型[编辑]

Mathematica是一门动态类型语言,这意味着一个变量的使用是无需事先声明的,而且同一个变量可以作为多种数据类型的占位符(并不推荐这样做)。事实上,这里根本没有传统编程语言里的那种类型的概念,类型的概念被原子和普通表达式替代。

任何新输入的对象都被当作一个符号实体。每当新的符号被输入,这个符号就被符号表检索。如果这个符号在符号表中已经存在,该符号的一个新的引用(reference)就被建立。如果不存在,一个新的条目就在符号表中被创造。如果这个对象是新的,或者没有能马上应用到它身上的规则,这个符号就被原样返回:

In[]:= Clear[a];
       a
Out[]= a
In[]:= Sin[a]
Out[]= Sin[a]

在最后一个例子里,Sin是一个内置符号,但是没有能应用在Sin[a]或者a上的规则,所以Sin[a]被原样返回了。

赋值[编辑]

立即赋值与延时赋值:Set和SetDelayed[编辑]

Mathematica里有两种赋值命令:立即赋值和延时赋值。

立即赋值用等于号"="表示,x=y表示“立即将y的值赋给x”。与这个命令等价的完全形式是Set,Set[x,y]就和前面的写法等价。":="用来表示延时赋值,比如x:=y。与":="等价的是SetDelayed,比如SetDelayed[x,y]。这表示“在全局规则库里添加一条规则,每当遇到x就将其替换为y在当时的值”。所以,如果使用延时赋值,等号右边的表达式在赋值的那一刻并不会被计算,而是在被赋值的表达式在程序的某一处出现时再重复计算。而Set在赋值那一刻计算就已经完成,这是两种赋值操作符的主要区别。

Set与SetDelayed的区别:举例说明[编辑]

这是一个例子:

In[]:=  Clear[a,b];
        a = Random[Integer, {1,10}];
        Do[Print[a]],{5}]
Out[]=  2
        2
        2
        2
        2
In[]:=  b:=Random[Integer, {1, 10}];
        Do[Print[b],{5}]
Out[]=  2
        6
        6
        10
        2

在两个例子中,一个符号(a或b)都被赋予了一个10以内的随机数。在前一个例子中,这个随机数在赋值时马上被计算并与a联系起来,但是在后一个例子中求随机数的函数在每次打印过程中都被重复计算。这里我们用到了一个循环结构Do,稍后会介绍。

Set和SetDelayed:该用哪一个?[编辑]

通常情况下,我们用Set(=)定义变量,用SetDelayed(:=)定义函数,因为函数通常要对不同的参数进行计算。然而,这里体现出了Mathematica和其它语言的不同:函数和变量的区别不是用类似于<function>的关键字来达到的,而是通过定义符号的不同方法达到的。一方面是通过两种不同的赋值操作符,另一方面是不同类型的全局规则(OwnValues和DownValues)。这就意味着函数和变量在Mathematica里可以同等看待。函数和变量之间没有本质差别这个特性是函数式编程的核心。函数式编程是Mathematica里最高效的编程范式之一,后面的章节会频繁使用。

检查表达式是否相等[编辑]

有两个检查相等的操作符,一个检查语义(表达式的值)的是否相等,一个检查表达式结构的是否相等。

Equal[编辑]

第一个操作符和很多语言(比如C语言)的一样,两个连续的等于号"==",比如x==y(完全形式是Equal[x,y])。Equal支持链式检查,所以类似于x==y==z(完全形式可以写做Equal[x,y,z])的写法是完全合理的(这一点就和C不一样了)。Equal可以拥有多个参数,这一点很方便:

In[]:= Clear[a,b,c];
       a=b=c=2;
       d=3;
       {a==b, b==d, a==b==c, Equal[a,b,c],Equal[a,b,c,d]}
Out[]= {True, False, True, True, False}

注意:Equal有时会罢工![编辑]

Equal对任何Mathematica表达式都起作用,包括原子和普通表达式。然而,当Equal不能判断两边的表达式是否有相同的值的时候就会原样返回:

In[]:= Sin[x]^2 + Cos[x]^2 == 1
Out[]= Cos[x]^2 + Sin[x]^2 == 1

但是这并不意味着Mathematica不能化简左边的表达式:

In[]:= Simplify[Sin[x]^2 + Cos[x]^2]
Out[]= 1

上面的例子仅仅表明在默认的情况下Mathematica不会去化解左边的那个式子。在这些情况下,Equal会以未计算的形式返回。这个特性在符号计算系统里是很有用的,有时新的规则会添加,没准这时Evaluate就能返回True或者False了:

In[]:= Simplify[Sin[x]^2 + Cos[x]^2==1]
Out[]= True

Equal被用来构建方程[编辑]

上面说的特性(拿不准的时候返回原式)被很多内置的与解方程相关的函数利用,比如Solve,DSolve等等:

In[]:= Solve[x^2-3 x + 2 ==0, x]
Out[]= {{x->1},{x->2}}

把Equal的结果赋给变量 再议计算[编辑]

就和其他的东西一样,Equal[a,b]也是表达式,所以我可以把这个表达式的值赋给变量,看看下面的例子:

In[]:= Clear[x,test];
       test= Sin[x]==0
Out[]= Sin[x]==0

现在我们给x赋值,再来看看结果:

In[]:= x = Pi;
       test
Out[]= True

赋值之前test返回的是未计算形式,但是一旦x被赋值,表达式test被计算成True。让人感到惊讶的是,此时test仍然拥有先前的定义,而不是变成了True:

?test
Global`test
test = Sin[x] == 0

特别地,如果我们此时把x的值Clear掉,结果又会变成符号表达式:

In[]:= Clear[x];
       test
Out[]= Sin[x] == 0

这意味着变量test事实上很像一个x的函数(这不是定义函数的合适方法!)。更重要的是,这向我们解释了一部分计算的机制。首先,test的定义代表了全局规则库中的一个规则,可以用OwnValues看到:

In[]:= OwnValues[test]
Out[]= {HoldPattern[test]:>Sin[x] == 0}

其次,通过Set添加的全局规则一旦被创建就不再改变——等于号右边的表达式在赋值时就被计算并被保存到规则库中。如果赋值的时候一些变量没有值,那么它们就会以符号的形式添加到规则库中。即使后来这些无值变量被赋了值,先前通过Set创建的定义(全局规则)也不会改变(除非被手动清除或改变)。这就是为什么在我们这个例子中test的定义总是保持不变,即使x的值在变化。

全局规则的状态和系统的状态是相互独立的,意识到这一点非常重要。全局规则的添加或清除只能通过规则库实现而与系统状态的改变无关。仔细想一想,这也是唯一可能的结果,因为系统的状态本身就是被全局规则库决定的。所以,刚才的讨论可以换个说法:在当前没有发生计算的情况下,添加到规则库中的若干条规则之间不会相互影响。如果不是这样的话,规则库里就会乱成一团,有的规则就会改变其它的规则!

幽灵般的副作用[编辑]

呃,Mathematica的符号特色可能会让人认为如果"=="两边的表达式完全一样的话,结果肯定是True。事与愿违,副作用总是会神出鬼没地影响着表达式的结果。在下面这个例子里,我们构建一个能使其参数“自增”的函数(不要理代码,后面会介绍)。

Clear[a,inc];
a = 5;
inc[x_]:=x=x+1;
Attributes[inc]={HoldAll}

看看结果:

In[]:= inc[a]==inc[a]
Out[]= False

你看出发生什么了吗?

题外话:标准与非标准计算[编辑]

很容易用Trace命令追踪上面到底发生了什么:

In[]:= a = 5;
       Trace[inc[a] == inc[a]]
Out[]= {{inc[a],a=a+1,{{a,5},5+1,6},a=6,6},{inc[a],a=a+1,{{a,6},6+1,7},a=7,7},6==7,False} 

我们能看到的是,首先左边的inc[a]被计算,在得出结果6的同时导致了一个副作用(a的值被改变了)。然后右边的inc[a]被计算,因为先前的a已经被改为6了,所以这次的结果是7,最后6==7得到False[5]

我用这个例子阐述以下几点。首先,子表达式inc[a]是在外层的Equal之前被计算的——这是Mathematica中的通用顺序,从叶到枝,从枝到干,从里到外。则被称作标准计算。然而,按照这个逻辑,上面例子中的a应该被首先计算啊?a在inc的里层,难道不应该先被计算成5吗?这是对的——正常情况下的确是这样。但是这里是个例外,a没有被首先计算,这叫做非正常计算(在这里是用HoldAll属性做到的,后面会介绍)。

正常和非正常计算对于Mathematica的功能实现都非常重要。大部分的内置函数按照“正常”模式进行计算,但是还有一部分重要的函数按“非正常”模式计算。这个话题现在谈太深入,我们以后会回头来详细介绍。

地址传递的模拟

这个例子还表明了另外一个观点,我们有可能通过一个函数去“真正地”改变参数的值(正如上面的inc函数所做的)。这有点像C语言中的传地址方式(由于Mathematica里没有指针,所以这句话并不完全正确)。然而在通常情况下,类似的东西很少在Mathematica编程中使用,因为函数一般在参数的拷贝上进行操作,而并不改变原来的参数。Mathematica函数能返回任意表达式(包含很多结果的表),而且内存动态分配(变量无需声明),模拟传地址语义真的很没必要!

SameQ

Equal的这些特性,尤其是“模凌两可”(返回未计算形式)这个行为,有时可能让人不太满意——需要的是"非真即假"的答案。这里还有另外一个操作符可以满足我们的需求。

这个操作符是三连等号“===”,比如x===y,完全形式写做SameQ,如SameQ[x, y]。SameQ比较的是表达式的“形”而非“义”。当表达式的形式上相同时返回True,否则返回False,再来看看前面的例子:

In[]:= Clear[x];
       Sin[x]^2 + Cos[x]^2 === 1
Out[]= False

有趣的是我们可以构造出Equal返回True而SameQ返回False的例子。比如下面这个:

In[]:= Pi/2 == Pi/2.
Out[]= True
In[]:= Pi/2 === Pi/2.
Out[]= False
这里两边的值虽然是相等的,但是形式却不一样:

 In[]:= {Pi/2, Pi/2.}
 Out[]= {Pi/2, 1.5708}

但是,反过来说是对的:如果SameQ给出True,则Equal必然给出True。

TrueQ

SameQ有时还是让人不太满意,因为当Equal给出True的时候它可能得出False。比如下面的情况:

In[]:= Clear[a, b, c, d];
       a := Equal[c, d];
       b := SameQ[c, d];
       {a, b}
Out[]= {c==d, False}
In[]:= c=Pi/2;d=Pi/2.;
       {a,b}
Out[]= {True, False}

这意味着,作为Equal的替代品,SameQ可能与Equal有着微妙的区别(不像Equal,SameQ总是给出True或者False)。这时另一个家伙就很方便了——TrueQ。这个函数在其参数不为True的时候给出False。所有,对于上面的例子,正确的做法应该是这样:

In[]:= Clear[a, b, c, d];
       a := TrueQ[Equal[c, d]];

检查结果:

In[]:= a
Out[]= False
In[]:= c = Pi/2; d = Pi/2.;
       a
Out[]= True
In[]:= Clear[a, b, c, d]

另外还补充两个函数,从字面上就能看出是干什么的:

  • Unequal
  • UnsameQ

逻辑运算符

和其他语言一样,Mathematica也有很多内置的逻辑运算符。我们介绍:

  • 逻辑与:And, 简写作"&&""
  • 逻辑或:Or,简写作"||"
  • 逻辑非:Not,简写作"!"

嗯,就如你看到的,这里的几个简写和C的写法完全一样。 这个算符返回True或False,在不能确定结果的时候也会原样返回:

In[]:= And[a, b]
Out[]= a&&b

这是这类算符和其它语言的最主要不同点,主要归因于Mathematica符号天性。当你需要确定的结果的时候,可以用TrueQ:

In[]:= TrueQ[And[a, b]]
Out[]= False

另外一点区别是And和Or可以有多个参数(C语言不能这样):

In[]:= And[a, b, c]
Out[]= a&&b&&c
In[]:= Or[a, b, c]
Out[]= a||b||c

And和Or还有和C相仿的“短路”性质:And在遇到一个False之后马上停止计数并返回False;Or在遇到一个True之后也马上停止计数并返回True。一般情况下参数是先于函数计算的,所以我们可以下结论说And和Or都用的是非标准计算。

条件

If

If的语法如下:

  • If[test,oper1,oper2]

这里的test是被检验的条件。原则上test的结果必须为True或False以便If做出选择。如果结果为真,oper1被计算,否则计算oper2。oper2可以省略,这时如果test的结果是False 就什么也不做并返回Null(代表“空”的关键字)。

你发现了吗?If用的也是非标准计算。后面两个参数不是在If之前计算的。

If也可能“罢工”

当条件test没能返回True或False的时候,If也会原样返回:

In[]:= Clear[a, b, c];
       If[a, b, c]
Out[]= If[a, b, c]

在这里我们能用TrueQ来确保能够进行,或者也可以利用If的第4个参数,这个参数在条件不能被明确判断的时候被计算:

In[]:= If[a, b, c, d]
Out[]= d

If返回一个值

“此If”和“彼if”的另外一点区别是Mathematica中的If不但会计算相应的表达式而且还会将结果返回。这很类似于C中的条件表达式a?b:c。所以下面的代码是有意义的:

In[]:= Clear[a, b, x, y];
       a:= If[EvenQ[b], x, y];

看一下结果:

In[]:= a
Out[]= y

EvenQ对于无法判断的情况总是返回False,上面的结果也就能解释了。

In[]:= b=2;
       a
Out[]= x

在试一次:

In[]:= b = 3;
       a
Out[]= y

注意到这里a的定义用了延时定义SetDelayed(:=)。再举个例子:

In[]:= Clear[a, x, y, test];
       a:= If[test, x, y];
       test := (Sin[x]==Cos[x]);
       a
Out[]= IF[Sin[x]==Cos[x],x, y]
现在:
In[]:= x=Pi/2
       a
Out[]= y
In[]:= x=Pi/4
       a
Out[]= Pi/4

Which和Switch

这两个命令拥有多分枝选择结构,可以代替嵌套的If。Switch和C语言里的switch相似,但是还是有显著的不同:Switch能配合模式一起使用;Break[]在此不起作用,所以C中fall-through现象就不能实现了(模式可以做一点补偿)。C语言中,switch可作为不同代码段的入口,在Mathematica里则不能。Which和Switch在帮助里说得很详细,以后要用到的时候再查阅。

循环

Mathematica里循环结构主要的模仿对象是C,不过逗号和分号的作用正好互换过来了。循环在Mathematica里一般不是很高效,更重要的是函数式风格的编程通常根本不会用到循环。不过为了完整性,在这里举几个简单的例子。

我们的例子为:打印数字1-5。

For循环

In[]:= For[i=1, i<=5, i++, Print[i]];
Out[]= 1
       2
       3
       4
       5

While循环

In[]:= i=1;
       While[i<=5, (Print[i];i ++)];
Out[]= 1
       2
       3
       4
       5

Do循环

In[]:= Do[Print[i], {i,1, 5}]
Out[]= 1
       2
       3
       4
       5

循环引起的副作用

通常Mathematica的内置函数式不会引起副作用的,因为它们的操作的都是说给表达式的拷贝。然而在For和While循环中,循环结束后循环变量然会保持最后的值,而且是全局的。把循环变量全部放进局部结构(Module,Block,With)里是个好习惯。

另一方面,Do循环本身就是局部结构,它自动将循环变量局部化。然而,和我们想的不一样的是,这种局部化是在时间上而非空间上进行的(和Block一样),后面会详细介绍。一般的:

In[]:= a:=i^2;
Do[Print[a], {i, 1, 5}]
Out[]= 1
       4
       9
       16
       25

i在循环结束后失去了值:

In[]:= i
Out[]= i

运算符的分块 CompoundExpression

小括号实则是一个组合运算符,在代码的任何地方都适用。它的完全形式是CompoundExpression[oper1;...;opern].各个操作直接用分号隔开。组合运算符的值是最后一个表达式的值(即opern)。特别地,如果我们在最后也加上分号,那么将没有返回值(更精确的说,返回的是空值Null)

要注意Do并不是C的do-while循环,而是For和While的快速版本,这个版本里没有边界条件需要检查,循环的次数是确定的。

局部跳转语句:Break,Continue,Return

Break[]和Continue[]可以用来实现局部的语句跳转。它们的工作方式和C里面差不多。比如我们让Do循环4次后停止:

In[]:= i = 1;
       Do[(Print["*"];If[i ++ > 3, Break[]]), {50}]
Out[]= *
       *
       *
       *

Return[]语句也可以用于从循环中退出,但是它的行为和Breakp[]不太一样。Mathematica里有三种局部化变量结构——Module,Block和With。如果这些结构中存在For或While循环,使用Break[]只能退出循环而且循环结构后面的代码会紧接着被计算。如果用Return的话情况就不一样了,Return能跳出整个局部结构(如果存在多重局部结构的话,跳出第一层)。但是对于Do循环不成立,Do本身就是一个局部结构,使用Return只能跳出Do而不包括外面的局部化结构。在熟悉Module,Block,和With之后你会更清楚。

循环通常很慢!

Mathematica里的循环效率通常都不是太高。这不因为循环本身非常慢,而是因为在其它语言里很高效的那种类似于For的循环模式反而在Mathematica里很慢。

我们用简单的例子示范一下。我们将求签100000个自然数之和。我们首先用循环,然后用函数式编程。

(*循环版*)
In[]:= Timing[sm =0;
                 Do[sm = sm + i,
             {1, 100000}];sm]
Out[]= {0.581, 5000050000}[6]
(*函数式版*)
In[]:= Timing[Apply[Plus, Range[100000]]]
Out[]= {0.16, 5000050000}

很明显函数式风格要快上好几倍!关于具体的原因会在下一章详细介绍。Timing给出的计算所用的总时间。

看来我让循环臭名远扬了。为了给它留点面子,在这里我要说,当能够使用内置的w:编译配合使用的时候,循环就快得不得了:

In[]:= Compile[{x,{n,_Integer}},
          Module[{sm=x},Do[sm=sm+i,
            {i, n}];sm]][0,100000]//Timing
Out[]= {0.03, 5.00005*10^9}

编译函数的只能达到机器精度,而且编译器不能编译通用对象。

Mathematica中的4种括号[编辑]

Mathematica使用4种括号,小括号,单方括号,双方括号,和花括号。每一种括号都有自己的含义和目的。

小括号[编辑]

小括号用来确定计算的优先级,用法和大部分语言一样。

花括号[编辑]

花括号表示一个(List)。完全形式是List:

In[]:= Clear[a, b, c];
       {a, b, c}===List[a, b, c]
Out[]= True

List表示对象(类型可以不一样)的集合,对于在程序中建立块状结构非常重要,因为任何复杂的数据结构都可以用其建立。下一章会完全奉献给List。

有些内置函数的参数也会用到List,比如Table,Do,以及前面说到的Level。

单方括号[编辑]

单方括号用来构建普通表达式。它们被用来表示任意的树状Mathematica表达式。这是它在Mathematica中存在的唯一目的(很重要)。

你可能会说方括号还能用来做函数调用呢:

In[]:= Sin[Pi]
Out[]= 0

然后,函数在Mathematica中是坐在第二把交椅上的,老大是规则和模式。所以,所有的函数调用到最后只是普通表达式的特例。Mathematica中没有独立的函数调用概念,它们都是用表达式和规则实现的。

双方括号[编辑]

最后双方括号被作为Part的简写,Part在前面介绍过,用途是从任意表达式里提取元素。一个普遍的错误是误将"[]"当作"[[]]"。一定要注意这两种方括号的区别。

总结[编辑]

我们了解了最基本的操作,赋值、比较、控制结构、循环。这里我们对于有些内容介绍得很简短,因为它们在正式的编程中很少用到。

本章还举了几个例子来说明Mathematica以规则为基础(rule-bases)的本质。这对于嗅到Mathematica和其它编程语言的不同之处很有帮助。

我们还学了一些函数:Clear、Set、SetDelayed、Equal、SameQ、If、Do、For、While、Apply、Range、Timing。

注记[编辑]

  1. 这里的Unevaluated的作用是防止里面的内容被计算,详见帮助
  2. 这个名词的翻译让我头疼,姑且先这么译了
  3. 可以借助通配符来一次清除多个变量,比如Clear["Golbal`*"]
  4. 为了防止一个页面的篇幅过长(好吧是我太懒了),一些不太重要的东西从略介绍,读者可以查阅帮助
  5. 这种现象不是Mathematica中特有的,在C语言中也会发生类似的现象把inc换成++试试?
  6. 时间测定可能在不同配置的计算机及版本之间有区别