网站最近更新

© 乙回庐 2019. All rights reserved.

Mathematica里最基本的那点知识:什么是表达式

咦,又是一个初学者的Mathematica教程,好无聊好无聊。但是我遗憾地发现好多教程都不提这些最最最基础的概念,原因有三:

  1. 读者不喜欢看: 基本概念都很抽象,用起来也不酷炫
  2. 读者不想看: 基本概念比较枯燥,而且初学并不常用
  3. 读者不想学: 基本概念理解起来看似简单,但是用法却千变万化,不利于读者十五分钟速成

不管怎么说,就是基本概念看着不酷、用得不多、用法复杂,所以最好不讲或者一句带过。而这个系列就要去翻翻这些最无聊的基本概念。那第一个Mathematica的知识点无疑是表达式。那什么是表达式呢?

Mathematica的文档里说得很好,Mathematica中所有的事物都是表达式。(其实并不是,比如注释不是表达式,为什么下面会解释)

Everything Is an Expression

好了,到此结束。你知道了所有关于表达式的内容,就是Mathematica中你看到的所有内容都是表达式。你懂了吗?就这句话,我反正不懂。如果你也不懂,那么就看下面的内容:

Mathematica中的表达式都可以表达为形如f[x,y,...]的形式,f是头,可以用Head查看;[]是一个语法结构表示里面的那个Sequencef的参数,x,y,...就是一个参数的序列,Mathematica叫Sequence。这个定义的后果是所有的事物都有头,下面是几个例子:

	In[1]:= Head[Sin[x]]	(* 注释:好理解 *)

	Out[1]= Sin

	In[2]:= Head[x]		(* 注释:默认的变量是Symbol [见注一] *)

	Out[2]= Symbol

	In[3]:= Head[1]		(* 注释:这个也还行 *)

	Out[3]= Integer

	(* 注释:Head的头是Symbol *)
	In[4]:= Head[Head]	

	Out[4]= Symbol

	(* 注释:Symbol的头和其他函数一样也是Symbol *)
	In[5]:= Head[Symbol]		

	Out[5]= Symbol

	(* 注释:Head[1]的头还是Symbol *)
	In[6]:= Head[Head[1]]		

	Out[6]= Symbol

	(* 注释:x+y的头是啥呢?这个为啥后面说 *)
	In[7]:= Head[x + y]		

	Out[7]= Plus

	(* 注释:注释的头是啥呢?不合法,所以注释没有头,也就不是表达式! *)
	In[8]:= Head[(* 注释 *)] 

	During evaluation of In[8]:= Head::argx: Head called with 0 arguments; 1 argument is expected. >>

	Out[8]= Head[]

由最后一句可以看到注释并不是表达式,因为表达式必须有头,所以Mathematica中有事物不是表达式,不过确实绝大部分都是表达式啦。下面回到x+y的头的问题,这是因为Mathematica中表达式可以表达为多种形式,也就是同一数据结构的多种表示方法,而x+y就是表达式的中置表示法。下面是Mathematica中表达式的常见表示方法的介绍:

  1. 前置表示法 f@Sequence[x, y, ...],参数只有一个的时候可以用f@x的形式表示。例如:

    Sin[x]可也写成Sin@xx怎么写成前置表达呢,我们知道他的头是Symbol,所以很容易得到x的前置表示为Symbol@"x";而x+y的前置表达是Plus@Sequence[x,y],这里有个矛盾也就是x+y的前置表达中包含了一个非前置表达Sequence[x,y],而Sequence[x,y]的前置表达又是Sequence@Sequence[x,y],如此可以一直下去。为了解决这个矛盾,Sequence[Sequence[x,y]]被定义为和Sequence[x,y]完全一样了。所以确实存在这么一个表达式,你无法用完全前置或者其他的方式表达出来。不过这是个特例。

  2. 中置表达法 x ~f~ y,对于参数为2的函数中置表达似乎很明显,x+y就可以看做一种中置表达,它和x ~Plus~ y是一样的。

    对于参数不等于2的情况,使用就比较不直观了。吸取前面前置表达法对于多个变量的表示方法,中置表达的多变量打开方式是x ~f~ Sequence[y,...]或者其他各种分割方法。对于只有一个参数的情况,留给读者思考,如果不能解决可以在留言中提问。

    另外提一句,Infix函数可以用来返回的表达式的中置表达,比如Infix@f[x, y]会返回x ~f~ y。但是,Infix@f[x,y,z]的返回是x ~f~ y ~f~ z,这并不是正确的表达方法,如果直接输入:x ~f~ y ~f~ z运行后直接返回的不是f[x,y,z],而是f[f[x, y], z]。准确的讲是仅对具有Flat属性的函数(见注二),这两个表达是一样的。

  3. 后置表达法 Sequence[x, y, ...] // f,参数只有一个时可以用x//f的形式表示。例如:

    Sin[x]可以写成x//Sin。多个参数的表达方法也一样留作练习,参考前置表达的表达方法应该不难解决。

上面三种表达法都是标准的f[x,y,...]的补充,主要是为了方便输入和增加可读性(如果看得懂的话)设置的,为什么那么说呢?比如

Simplify[f[x]]很常用,但是多加一层中括号,不仅不方便,而且随着括号层次增多就很难读。如果变成f[x]//Simplify就好多了,读法大概就是先计算f[x]然后化简。有时候前置表达可能更加易读,比如Last[f[x]]可以写成Last@f[x],可以大致读成最后一个元素@f[x]的计算值。中置运算符对于连接运算一类比较易读,比如Join[{1, 2}, {3, 4}]可以写成{1, 2} ~Join~ {3, 4}是不是好读很多。对于这三类表达方法,前置和后置一般用在单一参数的情况,中置一般用在两个参数的情况。其他情况,笔者建议最好使用标准的表示方法,也就所谓的StardardForm。这就引出了表达式的显示方式问题。

除了不同的表示法,表达式还有不同的显示方式,比如StardardForm, FullForm, TreeForm, TeXForm, CFormPostfix,Infix,Prefix等等等等。有些显示方式是可以完整转换的,比如StardardFormFullForm,有些则不能完整的转换,比如FullFormTeXForm。这些显示方式也有比较复杂的内涵,我们下次再说吧!

注一:x的Mathematica完整写法应该是Symbol@"x",类似地,Sin的写法是Symbol@"Sin"

注二:Flat属性是指:

Flat is an attribute that can be assigned to a symbol f to indicate that all expressions involving nested functions f should be flattened out. This property is accounted for in pattern matching. 

也就是说f[f[x, y], z]f[x, y, z]是一样的。

此文文长3077字,君不评论一二?
亲,给点评论吧!

展开本分类索引