mathematica-基于函数编程

前言

Mathematica基于过程的编程结构只是一个门面:内部更深层次的,是函数编程语言。

函数式编程范式中,函数和数据是没有区别的。函数可以和其他数据一样操控,包括作为参数和作为返回值。可以写个程序书写其他程序并且执行它们。这也是为何函数编程在人工智能领域如此流行的原因:它允许创造能在运行时修改它们行为的程序。

另外,函数程序没有赋值语句和循环。作为赋值的代替,数据严格通过函数调用和返回移动。作为循环的代替,高级函数作用函数到数据集合,或者使用递归。因为函数编程和过程编程如此不同,需要更多努力才能掌握,但是回报是产出优雅,精确和强大的程序的能力。

基本函数编程

Map和Apply

Map作用函数于表达式的每个子表达式并返回结果。Apply作用函数于表达式的所有子表达式一次并返回结果。

纯函数

使用Function定义纯函数:

Function[{x,y,...},body]

也可以使用简写形式(#表示参数,#1第一个参数,#2第二个参数,依次类推,&表示函数):

Sqrt[#]&

上面的表达式表示#的平方根函数。

层级指定

Level可以指定表达式的层级:

Level[list,lev]

lev的表示规则如下:

  • n表示1到n
  • {n}表示仅n层

MapAt

作用函数于表达式指定位置的子表达式。

同一个主题的变体

Map有很多的变体。

MapThread和Thread

MapIndexed

Through

Scan

迭代函数

给定迭代次数或者直到条件满足为止。

Nest

作用一个函数于返回值n次。

Nest[f,init,n]

FixedPoint

重复作用一个函数于返回值直到结果不变为止。

FixedPoint[f,init]

Fold

类似reduce,作用两个参数的函数于初始值和表达式的子表达式。

Fold[f,x,list]

Throw&Catch

抛出和捕获提供了一种改变Mathematica计算执行流的机制。Mathematica包含函数,例如Break, Continue,和Return,用于改变或终止循环和过程的执行。不幸的是,这些函数不能用于退出任何函数迭代结构。例如,当下面定义的函数f被传递给NestList时,f中的返回表达式对计算没有明显的影响:

In[3]:= f[x_]:=(If[x>5,Return[x+1]];2x)
NestList[f,1,6]
Out[4]= {1,2,4,8,9,10,11}

这种行为的原因是返回导致f而不是NestList返回。如果有某种方法可以同时从多个函数返回,这将非常有用。这就是Throw和Catch的目的。

In[29]:= Clear[f]
f[x_]:=(If[x>5,Throw[x+1]];2x)
Catch[NestList[f,1,3]]		
Out[31]= {1,2,4,8}

没有触发Throw,返回列表。

In[32]:= Catch[NestList[f,1,6]]
Out[32]= 9

触发了Throw,返回Throw里面的表达式。

递归

分而治之是一种算法策略,通过将问题分解成一个或多个相同类型的小问题来解决问题。这个过程一直持续到所考虑的问题非常小,以至于它们的解决方案微不足道。然后将子解组合成原问题的解。

递归是函数调用自身的行为。支持递归的编程语言(一个包含几乎所有现代语言的类)使得分治算法的实现非常简单。这是因为递归机制自动处理子解决方案的组合。

基础

毫无疑问,最著名的递归函数是阶乘:

In[34]:= Clear[fact]
fact[n_Integer]:=If[n==0,1,n fact[n-1]]
Array[fact,5]
Out[36]= {1,2,6,24,120}

如您所见,事实函数调用自身。这样做没有任何问题,只要“buck”在某处停止(在本例中,当n变为0时)。

要递归地解决一个问题,你必须考虑两种情况:

  1. 对于非平凡的情况,如何将问题简化为一个更小的问题(或几个更小的问题)。
  2. 基本情况是什么必须有一种方法来停止递归。

在列表上递归

反序排列

In[44]:= Clear[rev];
rev[s_List]:=If[s=={},{},Append[rev[Rest[s]],First[s]]];
rev[{1,2,3,4,5}]
Out[46]= {5,4,3,2,1}

递归的伟大之处在于,所有这些混乱的东西都可以通过普通的函数调用机制进行跟踪。递归允许我们在一个非常高的层次上对分而治之的问题进行推理,而细节则自行处理。

最小值

作为另一个简单的例子,这里有一个函数,它查找lis中的最小值。基本上,这个函数会查看列表中的前两个元素,然后在递归之前删除这两个元素中较小的那个。当只剩下一个元素时,它必须是最小值,因此返回它。

In[59]:= Clear[minimum];
minimum[s_List]:=Which[
	s=={},Infinity,
	Length[s]==1,s[[1]],
	s[[1]]>s[[2]],minimum[Drop[s,{1}]],
	True,minimum[Drop[s,{2}]]
];
minimum[{3,5,2,6,4}]
Out[61]= 2

归并排序

递归的一个更有趣的例子是用于排序列表的归并排序算法。

归并排序的策略是:

  1. 将列表分成两个大小差不多相同的部分。
  2. 递归地对每一块排序。
  3. 合并已排序的块。
In[66]:= Clear[mergesort]
mergesort[s_List]:=
Switch[
	Length[s],
	0,{},
	1,s,
	_,With[{half=Quotient[Length[s],2]},
	merge[mergesort[Take[s,half]],mergesort[Drop[s,half]]]
	]
];
merge[a_List,b_List]:=
Which[
	a=={},b,
	b=={},a,
	a[[1]]<b[[1]],Prepend[merge[Rest[a],b],a[[1]]],
	True,Prepend[merge[Rest[b],a],b[[1]]]
];
mergesort[{30,57,2,73,17,4,100,74,84,28,32,91}]
Out[69]= {2,4,17,28,30,32,57,73,74,84,91,100}

操作表达式

非原子表达式的一般结构是head[part1,…, partn],其中head和每个部分都是其他表达式,我们可以使用FullForm函数来探索各种表达式的内部表示,例如,

Plus[a,b]

下标表达式

类似面对对象语言的get方法,获取对象的单个属性。

Part[expre,{i,j,…}]

In[71]:= (a/b)//FullForm
Out[71]//FullForm= Times[a,Power[b,-1]]
In[72]:= (a/b)[[2,1]]
Out[72]= b

使用Position查询子表达式的位置:

In[73]:= Position[(a/b),b]
Out[73]= {{2,1}}

表达式层级

类似面对对象语言获取对象的所有属性。

如下表达式的树状图表示:

{a,b,{c,d,{e,f,g}}}

在这里插入图片描述
第一层的所有子表达式(类似对象的所有字段):

In[94]:= Level[{a,b,{c,d,{e,f,g}}},{1}]
Out[94]= {a,b,{c,d,{e,f,g}}}

第二层的所有子表达式:

In[95]:= Level[{a,b,{c,d,{e,f,g}}},{2}]
Out[95]= {c,d,{e,f,g}}

第三层的所有子表达式:

In[96]:= Level[{a,b,{c,d,{e,f,g}}},{3}]
Out[96]= {e,f,g}

1到1层的所有子表达式:

In[102]:= Level[{a,b,{c,d,{e,f,g}}},1]
Out[102]= {a,b,{c,d,{e,f,g}}}

1到2层的所有子表达式:

In[101]:= Level[{a,b,{c,d,{e,f,g}}},2]
Out[101]= {a,b,c,d,{e,f,g},{c,d,{e,f,g}}}

1到3层的所有子表达式:

In[103]:= Level[{a,b,{c,d,{e,f,g}}},3]
Out[103]= {a,b,c,d,e,f,g,{e,f,g},{c,d,{e,f,g}}}

等价于(把每一层的子表达式拼接起来)

In[104]:= Join[Level[{a,b,{c,d,{e,f,g}}},{1}],Level[{a,b,{c,d,{e,f,g}}},{2}],Level[{a,b,{c,d,{e,f,g}}},{3}]]
Out[104]= {a,b,{c,d,{e,f,g}},c,d,{e,f,g},e,f,g}

表达式上的函数操作

Map、Operate、Apply、MapAt等。

列表上的各种操作

FullForm、Drop、Append、Take、Reverse、RotateLeft、Join等。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值