Wolfram Language 学习笔记
大学四年,不应去追求成功,而应该追求自身的成长,找到自己可以持续投入的东西。——《CS 自救指北》CXS
Wolfram Language 是一种自由的语言,你可以用你喜欢的任何方式去学习它、使用它。我本希望通过它学习函数式编程 Functional Programming,无奈相关资源太少,最后还是决定从 Haskell 入门,研读《Haskell 趣学指南》,同时尝试用 Wolfram Language 实现书中的 Haskell 代码。
事实证明,这的确有一定挑战性:已经小成的 C/C++、刚入门的 Python,不学自会的 Java、正在学的 Haskell、Wolfram Language 快把爷整精分了。不过多语言同时学还是有点好处的,可以比较同一功能不同语言的实现,从而更深入地理解这一功能;“精分” 的过程同样也帮助了对不同语言语法的记忆。
在这里点名表扬 Wolfram Language 官方的文档,至少和 Python 是一个级别的了,非常详细。可惜入坑指南和 Python 比还有一定差距,过于简陋。所以本文也希望成为通过 Wolfram Language 学 FP 一篇不错的入坑指南。因为官方文档做的非常好,所以 凡是能通过看文档学的内容一律给文档链接,不再赘述。
调用函数
Wolfram Language 不仅支持普通的前缀调用,还支持以中缀、后缀的方式调用函数。合理使用这三种调用方式,能使代码逻辑清晰,增强可读性。
前缀调用
Reference: Prefix
@ 与 @@
注意区别
@ Prefix
与@@ Apply
:@
相当于一对中括号,而@@
会将其右边的函数头用左边的替换。1
2f @ g[x] <=> f[g[x]]
f @@ g[x] <=> f[x] (* g 被 f 替换 *)所以你知道下面四种写法结果不同的原因了吗?(提示:可以用
FullForm
函数观察表达式的完整形式,注意{}
只是语法糖,本质上也是函数调用)1
2
3
4Plus [1,2] (* Result: 3 *)
Plus [{1,2}] (* Result: {1,2} *)
Plus @ {1,2} (* Result: {1,2} *)
Plus @@ {1,2} (* Result: 3 *)Reference: Postfix with two arguments
@ 实现多参数调用
@
只能用于单参数调用,如果你实在想让@
支持多参数调用,有下面两种方案,分别对应参数后置、参数前置两种选择:1
2Plus @ Sequence[1,2,3] (* Result: 6 *)
Plus [#,2,3]& @ 1 (* Result: 6 *)第一种方法使用
Sequence
函数拼接参数序列,详细使用参见Sequence第二种方式使用纯函数语法改造原有函数。看上去这两种方法很有些费力不讨好的味道,但的确值得学习,这体现了 Wolfram Language 语法上的灵活性。
Reference: Stack Exchange: Difference between @ and @@
中缀调用
Reference: Infix
注意:中缀调用 ≠ 嵌套调用
1 | {1,2,3}~Join~{4,5,6}~Join~{7,8,9} <=> Join [{1,2,3},{4,5,6},{7,8,9}] |
后缀调用
Reference: Posfix
1 | {{1,2,3},{4,5,6},{7,8,9}} // Flatten // Total |
同样可以使用纯函数语法改造原有函数,以实现 多参数调用:
1 | 1 // Plus[#,2,3]& (* Result: 6 *) |
Map
Reference: Map
Apply
Reference: Apply
定义函数
Reference: 函数与程序
官方文档非常详细,这里不再赘述。但提醒一点:过程式语法中,函数体是用小括号 ()
,而不是中括号、大括号括起来的。可以显式地使用 Return
函数以设置一个或多个出口;也可以省去最后一个表达式末尾的分号,这样会默认返回该表达式的值。但可以看到,后一种方法最多也只能设置一个出口。
模式匹配
Reference: 规则与模式
x_
:只匹配 一个 表达式x__
: 匹配 1 个或多个 表达式x___
:匹配 0 个、1 个或多个 表达式
定义函数时使用模式匹配,可以省去一大串难看的 If 树。下面以 递归计算斐波拉契数列 和 快速排序 为例,体会模式匹配的强大:
1 | (*Fibonacci Sequence*) |
1 | (*Quick Sort*) |
纯函数
纯函数递归
Wolfram Language 中,#0
就是纯函数自己,可以用来实现纯函数递归。要在 Python 中实现这一点可不容易。
1 | If[#==1,1,#*#0[#-1]]&[3] (*计算 3 的阶乘*) |
函数组合
Reference: Composition
局部化变量
Reference: Module
Wolfram Language 中似乎没有一般编程语言中 作用域 的概念,所有变量如果不加约束,都是全局的。很多时候这会带来不便,比如下面版本的快速排序就因此无法得到正确的答案:
1 | qsort[{}]:={} |
1 | qsort[{}]:={} |
扔掉循环
如果你学过任何一门面向过程的编程语言,如 C++,那你一定学过循环结构。虽然 Wolfram Language 支持面向过程编程范式,C/C++ 的语法略作修改就能跑起来,但速度往往很不理想。
画图
Work with $\LaTeX$
MaTex 可以让我们协同使用 $\LaTeX$ 和 Wolfram Language 这两大神器,下面给出 Mac OS 的安装方法,其他平台安装方式见 GitHub 地址.
- 安装 MacTex
- 打开 Mathematica ,执行
ResourceFunction["MaTeXInstall"][]
即可安装 MaTex - 执行
<<MaTeX`
加载 MaTex(别丢了最后的反引号) - 输入
MaTeX["x^2"]
看看是不是已经能够使用了
XeLaTex 中文支持
MaTex 默认使用 PDFLaTex 渲染,但 Mac OS 上使用 XeLatex 会比 PDFLaTex 更方便:一来可以直接调用系统字体,二来原生 Unicode 支持不要太香。
一行命令将 PDFLaTex 换为 XeLatex:
1 | ConfigureMaTeX["pdfLaTeX" -> "/Library/TeX/texbin/xelatex"] |
下面添加常用中文宏包:
1 | SetOptions[ |
试试执行 MaTeX["Miao \\text{猫猫能有什么坏心眼呢}"]
,看中文是否已经可以显示。
自动加载
每次使用都要执行 <<MaTeX`
实在是有些麻烦,可以将其加入 init.m
中,实现打开时自动加载。修改 init.m
的具体方法参见 Wolfram 系统配置文件,init.m
Mac OS 下做如下修改即可:
1 | (** User Mathematica initialization file **) |
更多教程移步 开发者博客,在 Gitter 讨论组 获得帮助。