Mathematica软件使用教程 函数式编程

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Mathematica软件的函数式编程

本文由陆宇撰写,中国科学软件网发布

【前言】

作为Mathematica的开发商,Wolfram公司近几年致力于将其作为一门编程语言进行推广(这也是Wolfram公司改称

Mathematica为Wolfram Language的原因,本文仍沿用旧称)。如今也已经有了不少优秀的介绍Mathematica编

程的书籍,例如《Power Programming with Mathematica》、《Mathematica Programming:An Advanced

Introduction》、《An Elementary Introduction to the Wolfram Language》。尽管如此,但按照笔者经验,对于不少人来说,Mathematica还是很难上手,其独特的编程风格仍然很难适应。

由于使用方法不当(甚至是道听途说)造成了一个广泛的误解:

“Mathematica就是一个高级计算器,推推公式什么的还可以,遇到实际问题就不行了。”笔者回顾自己自学Mathematica的经历,也走过不少弯路,期间也不乏有如上那样的误解。作为“过来人”,笔者也对一些人在学习Mathematica过程中遇到的瓶颈也深有体会。本文就是从一个“过来人”的角度谈谈对Mathematica中函数式编程的理解。

笔者认为有些不恰当的前概念会阻碍Mathematica的学习。数学上认识的局限性,甚至是一些其他编程语言的“经验”,都有可能是阻碍学习Mathematica的症结所在。而对这些非技术方面的“意识”角度的探讨,现阶段的资料中还比较缺乏。原因之一也许是内容比较“虚”,不易做到“言之有物”。

笔者认为探讨这些“虚”的问题,还是通过举例子的方式为好。本文的主线不是解决某个具体的编程问题,而是围绕一些笔者认为重要的观念进行举例阐释,体现出

Mathematica的精妙设计之处,希望能对读者有所启发。限于水平,

对这些意识层面的探讨难免主观,也不可能面面俱到,本文权作引玉之砖。

【正文】

如Mathematica的名字本身所暗示的那样,

Mathematica的内部函数在设计的时候就带有一种浓厚的“数学味”,

使其在设计的时候远超“能用就行”的,具有数学家一样的认识深度和战略眼光。

例如,学过线性代数的人知道,对一组向量可以通过Gram-Schmidt正交化的步骤,把原本非正交的基底变为正交的基底,这其中需要不断地求投影。如果不知道Mathematica自带Orthogonalize这个函数也不要紧,可以自己用Projection模拟这个正交化过程,思路非常简单直接。例如这么写(摘自帮助文档,有改动):

gs[vecs_]:=Module[{ovecs=vecs}, Do[ovecs[[i]]-=Projection[ovecs[[i]], ovecs[[j]]],{i,2,Length[vecs]},{j,1,i -1}];

ovecs]

对于长的“像向量”的东西,例如数值的列表,这个确实运行得很好。例如可以通过下面的代码验证正交性:

b=gs[RandomReal[1,{3,3}]]

Chop@Outer[Dot,b,b,1]

Mathematica给出:

{{0.387954,0.0396196,0.222666},{0.0400743,0.434263,

-0.147091},{-0.302278,0.194557,0.492044}}和{{0.201658, 0,0},{0,0.211826,0},{0,0,0.371332}}.

最后的矩阵确实是对角的,因此程序正确!

向量的广泛一个认识是,它是有大小有方向的“东西”,这个“东西”在计算机中最自然和直接的表示方式是列表,在Mathematica中用一对大括号“{}”

括起来。尽管笔者也不怀疑,这个程序对于大多数情况是够用了。可如果对向量的认识仅限于一个个具体的列表,则未免让众多数学家们摇头感叹。

数学上的向量远超这种直观的理解,只要满足线性运算的八条规则的“东西”,都能叫做向量。定义了内积之后,这些向量之间就可以谈及正不正交。可没说向量就是由数字组成的列表。

如果读者仔细阅读Mathematica的Projection的使

用说明,会发现一个可以额外定义内积的第三个参数f:

Projection[u,v,f]finds projections with respect to the inner

product function f.

这里f可以定义两个“向量”怎么做内积。有了这个之后我们可以跳出“列表”向量的窠臼,得到所谓的“正交多项式”:

gs[vecs_,ip___]:=Module[{ovecs= vecs},

Do[ovecs[[i]]-=Projection[ovecs[[i]], ovecs[[j]],ip],{i,2,

Length[vecs]},{j,1,i-1}];

ovecs]

gs[{1,x,x^2,x^3},Integrate[#1#2,{x, -1,1}]&]

运行结果为:

{1,x,-(1/3)+x^2,-((3x)/5)+x^3}

除了整体的常数因子之外,这就是勒让德多项式(Legendre

Polynomials)!

当然,Mathematica可以直接用

Orthogonalize完成同样的事情:

Orthogonalize[{1,x,x^2,x^3},

Integrate[#1#2,{x,-1,1}]&]

居然还有如此简单的得到正交多项式的方法,不知读者是否感到惊叹呢?而一旦掌握了相关的数学知识,这种方法也并不神秘,只不过是真实地还原了数学的定义而已:向量可以是列表但不局限于列表,只要某个东西符合向量的“操作定义”它就可以称之为向量。

Mathematica中也有类似的哲学,函数可以对很自然地对某种类型的数据起作用,比如列表,但又有超出这种类型的时候。这种函数(数学上的映射)和实际数据(自变量)相互独立,也是函数式编程的一个特点。Orthogonalize 就是一个比较典型的例子。

除了体现编程中把一个函数的功能做专一且做到极致以外,如果没有一定的数学功底,意识不到数学上还有类似把多项式“正交化”这样的操作,则无论有多么高超的编程技巧也无法写出如此强大的函数。而一旦有这层意识,就会觉得这么设计是很自然的:函数就该有这个功能才对!

从其他编程语言转学Mathematica需要注意这种意识上的壁垒,有意识地反思是不是过于为机器或程序着想,抛弃一些照顾底层语言的习惯,跳出程序能用就行的实用主义,多查帮助文档,尤其是其中的Details、Backgrounds、Generalizations&

相关文档
最新文档