由于NestList函数的第一个参数要求是一个函数,因此其类型要么是函数头,要么是纯函数(可包含替换规则),而且这个函数只能有一个输入和一个输出(这里指的是Sequence形式,当然如果用列表输入,可以实现多输入或多输出,不过定义的形式上会有点差别,下面会提到这一点)。
现需要让NestList函数能作用在一个含参数的二元递归函数f上:
f: {p1,p2} -> {a*p1+b*p2, b*p1+a*p2}
因此我们需要将f定义为一个嵌套函数。也就是说,表达式f[args__]所返回的仍然是一个函数类型的表达式(比如f[1,2]得到的是一个参数a=1,b=2时候的一个二元递归函数,带有&符号的那种),而不是符号表达式。下面利用纯函数来嵌套定义:
f[a_, b_] :=
Function[{p1,
p2}, {{a,a*p1+b*p2},{a,b*p1+a*p2}}];
上面定义了一个以a,b为参数的函数,自变量为p1,p2。注意,如果不用嵌套定义,而是直接定义为f[a_,b_,p1_,p2_];=...(函数体省略) 那么将导致NestList无法使用,因为只有输入序列个数和输出序列个数相等才能实现迭代,而NestList输入序列个数只能是一个。
但问题是,自变量列表{p1,p2}其实定义的还是一个二元函数,即其自变量输入形式仍然是序列的。这种定义所要求的合法输入形式是f[1,2][x,y]这种,因此不符合要求。
将其改成单个输入,但是通过列表来传入多个参数:
f[a_, b_] :=
Function[{{p1,
p2}}, {{a,a*p1+b*p2},{a,b*p1+a*p2}}];
注意到上面的纯函数自变量列表是用双花括号表示{{}},即定义输入参数为一个列表,里面有两个元素(这就是我们要的两个自变量)。然而结果发现这种做法并不能得到想要的结果——运行f[1,2][{x,y}]出错,难道说上面的定义不能把输入的{x,y}自动替换为相应的{p1,p2}吗?
于是我想到干脆用参数的列表形式:
f[a_, b_] :=
Function[{p1p2}, {{a,a*p1p2[[1]]+b*p1p2[[2]]},{a,b*p1p2[[1]]+a*p1p2[[2]]}}];
这样输入一个列表,自动就能选取对应的变量代入函数中了:f[1,2][{x,y}]
得到结果{1, x + 2 y}, {1, 2 x + y}}
进一步,上面可以不用嵌套函数的定义方法,而是直接定义一个列表输入的函数:
f[var_List] := {{a, a*p1 + b*p2}, {a, b*p1 + a*p2}} /.
Thread@RuleDelayed[{a, b, p1, p2}, var];
运行f[{1, 2, x, y}],所得到的效果和上面一样。
问题虽然解决了,但是还是不清楚为什么既然Function函数可以定义Funciton[{{x,y}},...],那么说明就是定义{x,y}作为变量的纯函数,为何输入f[1,2][{u,v}]却得不到想要的结果?
不过上面的任何定义都不能进行迭代,因为返回值结构和输入值结构不同。因为a,b参数只是一个动态值,真正参与迭代过程的,是p1和p2,但是我需要记录a的值(因为后期会动态调整a,不断生成对应不同a值的迭代序列),这样才能绘制出散点图。如何改进?
现需要让NestList函数能作用在一个含参数的二元递归函数f上:
f: {p1,p2} -> {a*p1+b*p2, b*p1+a*p2}
因此我们需要将f定义为一个嵌套函数。也就是说,表达式f[args__]所返回的仍然是一个函数类型的表达式(比如f[1,2]得到的是一个参数a=1,b=2时候的一个二元递归函数,带有&符号的那种),而不是符号表达式。下面利用纯函数来嵌套定义:
f[a_, b_] :=
Function[{p1,
p2}, {{a,a*p1+b*p2},{a,b*p1+a*p2}}];
上面定义了一个以a,b为参数的函数,自变量为p1,p2。注意,如果不用嵌套定义,而是直接定义为f[a_,b_,p1_,p2_];=...(函数体省略) 那么将导致NestList无法使用,因为只有输入序列个数和输出序列个数相等才能实现迭代,而NestList输入序列个数只能是一个。
但问题是,自变量列表{p1,p2}其实定义的还是一个二元函数,即其自变量输入形式仍然是序列的。这种定义所要求的合法输入形式是f[1,2][x,y]这种,因此不符合要求。
将其改成单个输入,但是通过列表来传入多个参数:
f[a_, b_] :=
Function[{{p1,
p2}}, {{a,a*p1+b*p2},{a,b*p1+a*p2}}];
注意到上面的纯函数自变量列表是用双花括号表示{{}},即定义输入参数为一个列表,里面有两个元素(这就是我们要的两个自变量)。然而结果发现这种做法并不能得到想要的结果——运行f[1,2][{x,y}]出错,难道说上面的定义不能把输入的{x,y}自动替换为相应的{p1,p2}吗?
于是我想到干脆用参数的列表形式:
f[a_, b_] :=
Function[{p1p2}, {{a,a*p1p2[[1]]+b*p1p2[[2]]},{a,b*p1p2[[1]]+a*p1p2[[2]]}}];
这样输入一个列表,自动就能选取对应的变量代入函数中了:f[1,2][{x,y}]
得到结果{1, x + 2 y}, {1, 2 x + y}}
进一步,上面可以不用嵌套函数的定义方法,而是直接定义一个列表输入的函数:
f[var_List] := {{a, a*p1 + b*p2}, {a, b*p1 + a*p2}} /.
Thread@RuleDelayed[{a, b, p1, p2}, var];
运行f[{1, 2, x, y}],所得到的效果和上面一样。
问题虽然解决了,但是还是不清楚为什么既然Function函数可以定义Funciton[{{x,y}},...],那么说明就是定义{x,y}作为变量的纯函数,为何输入f[1,2][{u,v}]却得不到想要的结果?
不过上面的任何定义都不能进行迭代,因为返回值结构和输入值结构不同。因为a,b参数只是一个动态值,真正参与迭代过程的,是p1和p2,但是我需要记录a的值(因为后期会动态调整a,不断生成对应不同a值的迭代序列),这样才能绘制出散点图。如何改进?