我最近开始在 Logo 中编写非平凡的程序(在没有海龟图形的意义上非平凡)。我遇到的主要障碍之一是动态范围界定。例如考虑以下程序:
to foldl :f :acc :list [:index 1]
output ifelse empty? :list [:acc] [
(foldl :f (invoke :f :acc first :list :index) butfirst :list :index + 1)
]
end
to permute :list
output ifelse empty? :list [[[]]] [
foldl [[permutations item index]
sentence :permutations map [[list]
fput :item :list
] permute delete :index :list
] [] :list
]
end
该permute
函数适用于[]
它产生输出的空列表和它产生输出[[]]
的带有单个项目[a
] 的列表[[a]]
。但是,对于具有两个或更多元素的列表,它会失败。
猜猜为什么会失败?传递给foldl
from的 lambda 函数permute
访问了自由变量list
,并且因为foldl
还有一个名为它的局部变量list
,所以它访问了错误的变量。因为foldl
是递归定义的,所以list
变量会随着每次迭代而不断缩小。
我通过在函数中保存原始列表的副本解决了这个问题,foldl
如下所示:
to foldl :f :acc :list [:index 1] [:original :list]
output ifelse empty? :list [:acc] [
(foldl :f (invoke :f :acc first :list :index :original)
butfirst :list :index + 1 :original)
]
end
to permute :list
output ifelse empty? :list [[[]]] [
foldl [[permutations item index list]
sentence :permutations map [[list]
fput :item :list
] permute delete :index :list
] [] :list
]
end
然而,我花了晚上的大部分时间才弄清楚是什么导致了这个奇怪的错误。我以前从未使用具有动态范围的语言进行编程(保存一小段 bash 脚本)。
因此我的问题如下:用具有动态作用域的语言编写函数时应该记住什么?最佳实践是什么?如何避免常见的陷阱?