众所周知,Mathematica中虽然使用下标形式非常方便,但如果对下标结构进行直接赋值,它将关联到内部符号Subscript
上。这样,在我们大量清理符号定义的时候可能会漏掉一些定义。类似地,导数Derivative
有同样的问题,比如对于
1 | f'=df |
使用
1 | Clear[f] |
并不能清除f'
的定义。
虽说将直接赋值改为用UpSet
或者TagSet
替代可以将赋值关联到符号f
上而不是别的,比如下面的代码。
1 | f/:f'=df |
但每次多打一些东西总归是不方便,我们总会想找一个一劳永逸的办法。
官方文档中提到的对数量值的处理给了我启发。
在Wolfram语言中,数量值的处理与上值类似,当定义了
f
的数量值以后,Wolfram语言就象求值运算N
中f
的上值一样来输入这一定义.
下标的情况相对比较容易处理,类似an
的结构在Wolfram语言中实质就是Subscript[a,n]
,我们只要把普通的赋值转化为TagSet
即可,就如下面的代码所示
1 | Subscript /: Set[Subscript[a_Symbol, rest__], val_] := |
Derivative
的情况相对要复杂一些,因为即使看上去非常简单的f'[x]
在Wolfram语言内部也会表示为Derivative[1][f][x]
,我们认为的主要符号f
在这个表达式中层次太深,无法直接将TagSet
应用在上面,因此只能采取一些迂回的办法。
值得庆幸的是,Mathematica也支持纯函数式的导数,例如Sin'
会得到Cos[#1]&
。而在Derivative[1][f]
结构中,f
是可以通过TagSet
赋予上值的。对于这种情况,采用和前面类似的方法就能解决。
1 | Derivative /: Set[Derivative[ns__Integer][f_Symbol], val_] := |
而对于类似Derivative[1][f][x]
的情况,虽然我们无法直接对其使用TagSet
,但我们可以考虑将其转换为纯函数的情况。
动手前先分析,例如f'[x_]:=x
我们希望将其转换为f':=Function[{x},x]
,为了达到这个目的,需要去掉原本赋值中的模式结构:_
。
我们知道,像x_
的完整形式是Pattern[x,Blanck[]]
。因此,提取x_
的x
只要将其第一部分提取出来即可。综合一下可以写成如下的代码
1 | Derivative /: |
其中,Evaluate
是为了解决Function
的HoldAll
属性的。
除此之外,还有一点值得注意。像Derivative[1]
和Derivative[1,0]
是不同的,Derivative
的参数个数应该与被求导函数的参数个数匹配。
考虑了这个问题后,可以将上面的代码改成下面这样,以避免出现类似f'[x_,y_]:=df[x,y]
错误形式。
1 | Derivative /: |
当然,这种方法不能应对类似f'[1]=0
这样的单点导数赋值。但这种基于模式的单点导数定义本身也不是很合适的做法,比如
1 | f'[1]=0; |
其结果是无法体现出f'[1]=0
的。
因此对于一个函数的某阶导数,应该避免重载。如果有需要,也应该使用Piecewise
之类的手段整合成一个函数。