函数式操作

函数名作为表达式
在表达式如 f[x] 中,函数名称 f 本身也是一个表达式,可以像对待其他任何表达式一样对待.
可以使用转换规则替换函数名称:
所做的赋值用于函数名称:
定义一个以函数名称作为参数的函数:
给出 Log 用作函数名称:
能够把函数名称像其他类型的表达式一样对待,源于 Wolfram 语言的符号式本质. 这使得全范围的 函数式 操作成为可能.
普通的 Wolfram 语言函数(如 LogIntegrate)通常操作的是数字和代数表达式等数据,而代表函数式操作的 Wolfram 语言函数不仅可以对普通数据进行操作,还可以对函数本身进行操作. 例如,函数式操作InverseFunction 以 Wolfram 语言函数名称作为参数,来表示该函数的反函数.
InverseFunction 是一个函数式操作:将 Wolfram 语言函数作为参数,返回该函数的反函数.
InverseFunction 获得的结果也是一个函数,可以应用于数据:
还可以以纯符号方式使用 InverseFunction
Wolfram 语言中有很多种函数操作,有些代表数学运算;有些代表各种程序和算法.
除非您对高级符号语言非常熟悉,否则可能并不认识所讨论的大多数函数操作. 这些操作看上去似乎很难理解,但不要放弃. 函数操作是从概念学习到实际应用 Wolfram 语言最有效的方法之一.
重复应用函数
许多程序会涉及多次迭代的操作. NestNestList 是执行此操作的强大结构.
Nest[f,x,n]
将嵌套 n 次的函数 f 应用于 x
NestList[f,x,n]
生成列表 {x,f[x],f[f[x]],},其中 f 的嵌套层深为 n
重复应用一个参数的函数.
Nest[f,x,n] 接受函数的名称 f,并将函数 n 次应用于 x
将给出每个后续嵌套的列表:
一个简单函数:
可以使用 Nest 迭代该函数:
NestNestList 可用于将函数应用固定的次数. 通常,函数要应用到结果不再更改为止. 这可以使用 FixedPointFixedPointList 来实现.
FixedPoint[f,x]
重复应用函数 f 直到结果不再更改
FixedPointList[f,x]
生成列表 {x,f[x],f[f[x]],},当元素不再更改时停止
应用函数,直到结果不再更改为止.
函数对 进行牛顿逼近的一步:
函数的五个连续迭代,从 开始:
使用函数 FixedPoint,可以自动连续应用 newton3 直到结果不再更改为止:
结果的数列:
NestWhile[f,x,test]
重复应用函数 f,直到对结果应用 test 不再产生 True
NestWhileList[f,x,test]
生成列表 {x,f[x],f[f[x]],},当对结果应用 test 不再产生 True 时停止
NestWhile[f,x,test,m]
,
NestWhileList[f,x,test,m]
提供 m 个最新结果作为每一步 test 的参数
NestWhile[f,x,test,All]
,
NestWhileList[f,x,test,All]
提供现有的所有结果作为 test 的参数
重复应用函数直到测试失败.
这是一个函数,将数值除以 2:
重复应用 divide2,直到结果不再是偶数:
重复应用 newton3,直到两个连续结果不再视为不相等时停止,就像在 FixedPointList 中一样:
一直进行到已经出现过的结果再次出现为止:
Nest 等操作接受一个单参数的函数 f,然后重复应用. 每一步都将上一步的结果用作 f 的新参数.
将这一概念推广至两个参数的函数是很重要的. 您可以再次重复应用该函数,但现在获得的每个结果仅提供所需的新参数之一. 一种简便的方法是在每个步骤中从列表的连续元素中获取另一个参数.
FoldList[f,x,{a,b,}]
创建列表 {x,f[x,a],f[f[x,a],b],}
Fold[f,x,{a,b,}]
给出由 FoldList[f,x,{a,b,}] 生成的列表的最后一个元素
重复应用双参数函数的方法.
FoldList 的用法示例:
Fold 给出由 FoldList 生成的列表的最后一个元素:
给出了累积和的列表:
使用 FoldFoldList 可以在 Wolfram 语言中编写许多优雅高效的程序. 在某些情况下,将 FoldFoldList 视为由第二个参数索引的一组函数的简单嵌套可能会有所帮助.
定义函数 nextdigit
以下函数与内置函数 FromDigits 的作用一样:
函数的运行示例:
对列表和其他表达式应用函数
在像 f[{a,b,c}] 这样的表达式中,列表是函数的参数. 但是很多时候我们需要将函数直接应用于列表的元素,而不是整个列表. 这在 Wolfram 语言中可以使用 Apply 实现.
使列表的每个元素都成为函数 f 的参数:
给出了 Times[a,b,c],生成列表中元素的乘积:
使用 Apply 编写的函数定义,类似于内置函数 GeometricMean
Apply[f,{a,b,}]
f 应用于列表,给出 f[a,b,]
Apply[f,expr] or f@@expr
f 应用于表达式的顶层
MapApply[f,expr] or f@@@expr
f 应用于表达式的第一层
Apply[f,expr,{1}]
等价于 f@@@expr
Apply[f,expr,lev]
f 应用于表达式的指定层
将函数应用于列表和其他表达式.
一般来说,Apply 的作用是用指定的函数替换表达式的标头. 在这里是用 List 替换了 Plus
一个矩阵:
在没有明确指定层的情况下,使用 Apply 会将顶层列表替换为 f
仅将 f 应用于 m 在第1层的部分:
MapApply 相当于在第1层上对部分使用 Apply
f 应用于0至1层:
对表达式的部分项应用函数
如果有一个元素列表,将函数分别应用于列表中每个元素通常很重要. 在 Wolfram 语言中这可以使用 Map 完成.
f 分别应用于列表中的每个元素:
定义一个函数,该函数选取列表中的前两个元素:
可以使用 Maptake2 应用于列表的每个元素:
Map[f,{a,b,}]
f 应用于列表的每个元素,给出 {f[a],f[b],}
将函数应用于列表中的每个元素.
Map[f,expr] 实际上做的是将函数 f 封装在表达式 expr 的每个元素周围. Map 可以用于任何表达式,而不仅仅是列表.
f 应用于和式中的每个元素:
Sqrt 应用于 g 的每个参数:
Map[f,expr]f 应用于 expr 中各部分的第一层. 使用 MapAll[f,expr] 可以将 f 应用于 expr所有部分.
定义一个 2x2 矩阵 m
Mapf 应用于 m 的第一层,在这里是矩阵的行:
MapAllf 应用于 m全部层. 如果仔细看一下这个表达式,会发现各部分都已被 f 封装:
通常,可以使用表达式的层中所述的层规范来告诉 Map 将函数应用到表达式的哪些部分.
f 仅应用于 m 在第2层的部分:
设置选项 Heads->True 将每个部分的标头及其元素用 f 封装:
Map[f,expr] f/@expr
f 应用于 expr 的第一层部分
MapAll[f,expr] f//@expr
f 应用于 expr 的所有部分
Map[f,expr,lev]
在由 lev 指定的层上将 f 应用于 expr 的各个部分
将函数应用于表达式的不同部分的方式.
可以通过指定层的方法用 Map 将函数作用于表达式的一些项上. 通过指定层次可以使函数作用于表达式的某些项上,用MapAt 可以通过列出元素标号使函数作用于表达式的某些项上,请参见 "表达式的部分".
定义 2x3 矩阵:
f 作用于 {1,2}{2,3} 的项上:
给出 bmm 中出现的位置:
可以将 Position 得到的值代入 MapAt 中去:
为了避免混淆,即使在仅有一个下标时,也应该以列表的形式指定每一项:
MapAt[f,expr,{part1,part2,}]
f 作用于 expr 中指定的项
将函数作用于表达式中指定的项.
定义表达式:
给出 t 的完全格式:
MapAt 可用在任何表达式中. 注意,其中指定项的索引是基于表达式的完全格式:
MapIndexed[f,expr]
f 作用于表达式的元素,f 的第二个变量给出表达式的每个元素项的位置
MapIndexed[f,expr,lev]
f 作用于表达式指定层的元素,f 的第二个变量给出表达式中每项的指标号
函数作用于表达式中的项和其标号上.
f 作用于一个列表的每个元素上,其第2个自变量给出元素的标号 f
f 作用于矩阵的所有层:
Map 把一元函数作用于一个表达式的项上;MapThread 将多元函数作用于多个表达式.
MapThread[f,{expr1,expr2,}]
f 作用于每个表达式 expri 中对应的项
MapThread[f,{expr1,expr2,},lev]
f 作用于 expri 的指定层
同时将函数作用于多个表达式.
f 作用于相应的元素:
MapThread 可对结构相同的任意长度的表达式进行操作:
Map 等函数可以通过项的修改产生表达式,但有时不需要产生新的表达式,仅需要查看某些表达式,或者仅对表达式中的某些项进行运算. 一个典型的情况是当你所运用的函数具有某些 副作用 时,如进行赋值或产生输出时.
Scan[f,expr]
求出 f 作用于 expr 中各项时的函数值
Scan[f,expr,lev]
求出 f 作用中 expr 中第 lev 层项时的函数值
计算表达式中各项的函数值.
Mapf 作用于一个列表而产生新的列表:
Scan 计算将函数作用于每一个元素的结果,但不产生新的表达式:
Scan 从最低层开始访问表达式中的所有项:
纯函数
Function[x,body]
纯函数中的 x 可用任何变量代替
Function[{x1,x2,},body]
多变量的纯函数
body&
自变量为 ##1#2#3 等的纯函数.
纯函数.
使用 NestMap 等函数运算时,总需要有一个确定函数名的函数去作用. 纯函数可直接作用于变量,不需要函数名.
定义函数 h
Map 中使用刚定义的函数名 h
用纯函数得到相同的结果:
Wolfram 语言中的纯函数有多种形式. 最理想的情况是定义一个目标函数,其作用于一个变量时给出函数值. 因此,如 fun[a] 计算纯函数 funa 的值.
求平方的纯函数:
可以用纯函数名调用 n 计算 n 平方的值:
Map 中使用纯函数:
在嵌套 Nest 中用纯函数:
定义一个纯函数,并求出作用于 ab 的值:
当需要重复使用一个函数时,可以先用 f[x_]:=body 定义函数,然后再使用名字 f 调用. 而当仅使用函数一次时,用纯函数就比较方便.
熟悉形式逻辑和 LISP 编程语言的人会体会到 Wolfram 语言中的纯函数与 表达式或无名函数相似,纯函数也类似于数学中的运算符.
#
纯函数中的第一个变量
#n
纯函数中的第 n 个变量
##
纯函数中的所有变量列
##n
纯函数中从 n 个变量开始的变量列
纯函数的简单形式.
正如如果你不想再次提到该函数的话,函数名是无关的,因此同样地,一个纯函数中的变量名也是无关的. Wolfram 语言允许用户不使用纯函数变量的显式名字,另一方面,我们可以通过给出位置数字 #n 来指明变量. 在一个 Wolfram 语言纯函数中,#n 表示所提供的第 n 个变量. # 表示第一个变量.
#^2& 是求变量平方的纯函数的简化形式:
下面将应用一个获取每个列表的前两个元素的函数. 通过使用纯函数,可以避免再单独定义函数:
利用纯函数的简化形式简化前面重复应用函数fromdigits 函数的定义:
当使用纯函数的简化形式时,千万不要忘记 & 号,否则 Wolfram 语言就无法理解和执行这一输入.
在纯函数中使用 & 符号时,要注意 & 的优先级很低,必要时要用括号,如运算符的输入形式中讨论的. 这意味着,你可以不用括号输入形如 #1+#2& 的表达式. 另一方面,如果你愿意对纯函数设置选项话,必须使用括号. 例如,option->(fun&).
在 Wolfram 语言中,纯函数可以选择任何数目的变量. ## 表示给定的任何变量,##n 表示从第 n 项开始的所有变量.
## 代表所有变量:
##2 表示除第一项以外的所有变量:
用函数产生列表
Array[f,n]
产生形如 {f[1],f[2],} 的长度为 n 的列表
Array[f,{n1,n2,}]
产生 n1×n2× 的嵌套列表,每个元素是 f 作用于其标号上得到的
NestList[f,x,n]
产生形如 {x,f[x],f[f[x]],} 的列表,其中 f 迭代 n 次为止
FoldList[f,x,{a,b,}]
产生列表 {x,f[x,a],f[f[x,a],b],}
ComposeList[{f1,f2,},x]
产生列表 {x,f1[x],f2[f1[x]],}
由函数产生列表.
构建 5 个元素的列表,每个元素为 p[i]
另一种产生同一列表的方法:
产生元素为 的列表:
产生元素为 m[i,j] 的 2×3 矩阵:
产生一个 3×3 的矩阵,其中的元素为该元素下标的平方和:
NestListFoldList 曾经在重复应用函数中描述过. 尤其在将其与纯函数结合的时候,可以构造一些非常有效的 Wolfram 语言程序.
关于 逐次求导得到列表:
用函数选择表达式的项
"处理列表元素" 介绍了如何根据 位置 在列表中选取元素. 经常也需要根据内容来选取元素,而不是根据位置选取.
Select[list,f] 选择 list 的元素以 f 为判据. Selectf 依次用于 list 的每个元素,并且只保留结果为 True 的元素.
选取令纯函数生成 True 的列表元素,即数值大于4:
可以使用 Select 选取任意表达式的项,不仅仅局限于列表的元素.
给出包含 xyz 的项的和:
可以使用 Select 从和式中选取不包含符号 x 的项:
Select[expr,f]
选择 exprf 值为 True 的项
Select[expr,f,n]
选择 expr 中前 nf 值为 True 的项
选择表达式中的项.
"限制模式" 节介绍的一些判断词常常用来作为 Select 的判据.
此语句给出了满足选择条件的第一个元素:
具有非符号头部的表达式
大部分情况下,我们希望像 f[x] 这样的表达式的头部 f 是一个简单符号,但具有非符号头部表达式也有一些重要应用.
f[3] 是表达式的头部. 可以用这样的头部表示指定的函数:
可以用任何表达式作头部. 但必须放在括号内:
将一个复杂的表达式用作头部的情况在 "纯函数" 节已遇到. 将 Function[vars,body] 作为表达式的头部时就定义了对变量求值的函数.
头部为 Function[x,x^2] 的表达式的值是其变量的平方:
在 Wolfram 语言中有一些类似于纯函数的结构,其用来表示数值函数等一些特殊的函数. 在所有情况下,基本机制是给出能够包含所需要的函数完整信息的头部.
Function[vars,body][args]
纯函数
InterpolatingFunction[data][args]
InterpolationNDSolve 产生的近似数值函数
CompiledFunction[data][args]
Compile 产生的编译数值函数
LinearSolveFunction[data][vec]
LinearSolve 产生的矩阵解函数
一些有非符号头部的表达式.
NDSolve 返回一系列规则,这些规则将 y 作为 InterpolatingFunction 的目标:
InterpolatingFunction 目标作为头部去得到函数 y 的数值近似:
复杂表达式作为头部的另一个重要应用是进行泛函运算.
考虑一个求导运算的例子,在 "导数的表示" 节将要讨论的表达式 f' 求函数 f 的导数,在 Wolfram 语言中 f'Derivative[1][f] 表示,函数操作符 Derivative[1] 作用于 f 后给出另一个函数 f'.
表达式的头部表示将功能运算 Derivative[1] 作用于函数 f
你可以用其他标头取代 f',例如,fp. 这将有效地将 fp 作为从 f 获取的导数函数
算子运算
可以将表达式 f[x] 理解为算子 f 作用于表达式 x 上. f[g[x]] 可以理解为算子 fg 复合作用于 x 上的结果.
Composition[f,g,]
函数 fg 的复合
RightComposition[f,g,]
fg 的右侧的复合
InverseFunction[f]
f的反函数
Identity
恒等函数
一些函数运算.
fgh 的复合:
可以对复合函数进行符号运算:
当指定了一个变量时,就可以明确地给出复合的值:
可用操作符 @* 输入复合:
RightComposition 按想法顺序进行复合:
用操作符 /* 可从右开始进行复合:
在 Wolfram 系统中用 x+y 可以得到两个表达式的值. 有时,在算子运算中也可以考虑算子的和.
算子 fg 的和:
Through 可以使上面的表达式更加明确:
算子
Wolfram 系统不会主动将算子的几项作用于一个表达式:
Through 去作用这一算子:
Identity[expr]
恒等函数
Through[p[f1,f2][x],q]
pq 相同时给出 p[f1[x], f2[x]]
Operate[p,f[x]]
得到 p[f][x]
Operate[p,f[x],n]
f 的第 n 层运用 p
MapAll[p,expr,Heads->True]
p 作用于 expr 的头部和所有项
算子运算
该表达式有一个复杂的头部:
Expand 这样的函数不会自动作用于表达式的头部:
当可选项 Heads 设定为 True 时,MapAll 作用于头部之内:
替代运算 /. 进入表达式的头部:
可以用 Operate 将某一函数作用于表达式的头部:
结构的操作
Wolfram 语言有改变表达式结构的有效功能. 这可以使我们实现合并、分配等数学特性,并对一些简洁和有效的程序提供基础.
我们描述各种对表达式进行的操作. "属性" 介绍一些操作如何自动在所有具有特定头部并且该头部被赋以适合的属性的表达式上进行.
Wolfram 语言函数 Sort[expr] 不仅排列列表元素,也对具有任意头部的表达式排序. 用这种方式,我们可以对任意函数实现结合特性或对称性.
Sort 将函数的变量按序排列:
Sort[expr]
按照一种标准顺序对列表或表达式的元素分类
Sort[expr,pred]
pred 函数决定是否按顺序排列
Ordering[expr]
当排好序时,给出元素的顺序
Ordering[expr,n]
当排好序时,给出前 n 个元素的顺序
Ordering[expr,n,pred]
使用函数 pred 来决定是否每对都是排好序的
OrderedQ[expr]
当表达式 expr 的元素按标准顺序排列时为 True,否则为 False
Order[expr1,expr2]
expr1 按标准顺序出现在 expr2 前时取值 1,相反时取值 -1
按顺序分类.
Sort 的第二个变量是用于决定是否每对都是排好序的函数. 排序按递减顺序进行:
根据不含 x 的元素比含 x 的元素靠前的次序排列:
Flatten[expr]
压平与 expr 具有相同头部的嵌套函数
Flatten[expr,n]
最多取消 n 次嵌套
Flatten[expr,n,h]
撤销以 h 为头部的函数的结构
FlattenAt[expr,i]
撤销表达式 expr 中的第 i 层结构
压平表达式的结构.
Flatten 压平函数嵌套:
Flatten 将元素 拼接 为列表或其他表达式:
可以使用 Flatten 进行组合. 函数 Distribute 允许你实施特性,例如,分配特性和线性.
Distribute[f[a+b+,]]
f 分配到和式去得到 f[a,]+f[b,]+
Distribute[f[args],g]
f 分配到头部为 g 的变量
Distribute[expr,g,f]
当头部为 f 时分配
Distribute[expr,g,f,gp,fp]
f 分配到 g,并分别用 fpgp 代替
分配律.
f 分配a+b
更复杂的一些例子:
一般地,f 分配到和式 Plus 时,是将如 f[a+b] 的表达式 展开f[a]+f[b]. 函数 Expand 对标准的代数乘法如 Times 进行类似的分配展开. Distribute 可对任意运算进行类似的分配展开.
Expand 实施乘法 Times 对加法 Plus 的分配:
对一个列表,而非和式,进行分配. 结果包含所有可能的变量对:
当表达式的头部为 f 时,对其进行分配:
当头部是 f 时,对列表进行分配. 结果,用 gp 代替列表 List,用 fp 代替 f
Distribute 相关的是函数 Thread. Thread 将函数并行地作用于一个列表或表达式的所有项.
Thread[f[{a1,a2},{b1,b2}]]
f 线性作用于列表给出 {f[a1,b1],f[a2,b2]}
Thread[f[args],g]
f 线性作用于头部为 g 的变量 args
线性作用于表达式的函数.
变量是列表的函数:
Thread 线性作用于列表的元素:
不在列表中的元素将重复:
"将一些对象放在一起" 中提到,并且在 "属性" 中有更详细的讨论,Wolfram 语言的许多内置函数具有 可列表 的性质可以自动进行线性作用.
内置函数,比如 Log 是可列表的,因此可以自动逐项作用于列表:
Log 不能自动对方程进行线性作用:
可以用 Thread 使函数作用于方程两端:
Outer[f,list1,list2]
广义外积
Inner[f,list1,list2,g]
广义内积
广义内积和外积.
Outer[f,list1,list2] 给出 list1list2 中元素所有可能的组合,并将 f 作用于这些组合. Outer 可以看作是张量的积的推广,如 "张量" 中讨论的.
Outer 给出了元素的所有组合,并用 f 作用:
Outer 产生一个下三角 Boolean 矩阵:
Outer 可用于任何头部相同的表达式:
Distribute 一样,Outer 给出元素所有可能的组合,而 InnerThread 一样仅给出表达式中相应位置元素的组合.
Inner 形成的结构:
Inner 是内积 Dot 的推广:
序列
函数 Flatten 撤销所有的子列表:
FlattenAt 撤销指定的子列表结构:
Sequence 序列对象中的元素自动进行拼接,而不要求任何显式的压平操作:
Sequence[e1,e2,]
序列的元素自动拼接到函数
函数变元中序列的表示.
Sequence 用于各种函数:
用于有特殊输入格式的函数:
Sequence 的常用方式: