wxMaxima/Maxima的makelist是串行还是并行执行?能否递归生成依赖前项的列表?
Maxima makelist 生成递归依赖列表异常问题
问题描述
- 需求:创建递归定义的列表,即第
term[i]项是term[i-1]的函数,而非直接由索引i推导得到 - 预期逻辑:若
makelist为串行执行,生成第i项时直接调用已生成的列表前序项应当可正常求值 - 疑点:Maxima官方文档未明确说明
makelist生成列表项的执行顺序
测试过程
注:本示例的输出可直接通过索引函数实现,此处仅用于测试
makelist内部调用前序项的能力。
测试代码如下:
test: makelist(block([ ], /* list item set to 1 for first term of the list, and to previous list item, thereafter */ if i = 1 then addend else test[i-1] ) , i, 5);
实际运行返回结果为[1, test[1], test[2], test[3], test[4] ],并未实际访问test的已有值。
已尝试的排查操作包括:提前初始化test、在block中重新绑定test(例如block([ test:test ], ...),均无法得到预期结果。
问题原因
赋值时机不匹配:test: makelist(...)的赋值动作会等makelist完全执行完毕、整个列表全部生成后才会触发。在makelist循环生成每一项的过程中,test仍处于未绑定(或保留旧值)的状态,因此访问test[i-1]时无法读到已经生成的前序项,只能返回未求值的符号表达式。
你尝试的block([ test:test ], ...)无效的原因也相同:block执行时拿到的test还是未赋值的旧值,局部绑定也无法获取循环过程中动态生成的前序项。
解决方案
方案1:显式循环逐次更新列表(推荐)
放弃makelist,改用for循环逐次生成每一项,每生成一项立刻追加到目标列表中,下一次循环即可直接访问最新的前序项:
/* 先初始化空列表 */ test: []$ for i: 1 thru 5 do ( if i = 1 then /* 第1项赋值为初始值addend,追加到列表末尾 */ test: append(test, [addend]) else /* 后续项直接等于列表的最后一个元素 */ test: append(test, [test[-1]]) )$ test; /* 运行后可得到预期的递归结果 */
方案2:makelist内部维护临时累计状态
如果必须使用makelist,可以在循环内部维护一个独立的临时列表,存储已生成的前序项,不再依赖外部的test变量:
/* 先清除旧的临时变量,避免残留值干扰 */ kill(acc)$ test: makelist( block( /* 计算当前项:第1项用初始值,后续项取临时列表的最新元素 */ item: if i = 1 then addend else acc[1], /* 将当前项存入临时列表(用cons前插效率更高) */ acc: cons(item, acc), /* 返回当前项作为列表元素 */ item ), i, 1, 5 );
内容的提问来源于stack exchange,提问作者Rax Adaam
相关产品推荐
相关产品推荐

