Clojure core.logic查询变量处于特定位置时程序不终止问题咨询
问题1:为什么查询变量处于特定位置时,通用查询会不终止?
core.logic采用深度优先搜索的执行策略,你实现的reverso函数对子句顺序、目标执行顺序敏感,且默认对参数的实例化状态有偏向性:
- 当执行
(run* [q] (reverso q [1 2 3]))时,第二个参数是已实例化的固定长度列表,每次递归时拆分列表的操作(conso/appendo/conjo2)的长度都会减1,递归深度被严格限制在列表长度值,自然可以正常终止并返回结果。 - 当执行
(run* [q] (reverso [1 2 3] q))时,第二个参数是未实例化的逻辑变量,拆分操作可以生成无限多的可能绑定(比如尝试长度为4、5、6……的列表匹配),深度优先搜索会一直进入递归分支,永远碰不到空列表的终止条件,就会陷入无限循环。
你替换为core.logic/conjo后触发问题的参数位置变化,本质是内置conjo的子句顺序、目标执行顺序和你自定义的conjo2相反,适配的实例化参数位置不同,自然出问题的场景会反过来。
问题2:为什么run 1可以正常得到结果,run 2就会立刻不终止?
run n的语义是返回前n个满足条件的解:
- 当你调用
run 1时,core.logic会先搜索到长度匹配的第一个正确解,拿到结果后就会直接返回,不会进入后续的无限递归分支。 - 当你调用
run 2时,core.logic在返回第一个解之后,会继续搜索第二个可能的解,此时就会进入无限递归的分支,尝试生成更长的列表匹配,永远不会找到第二个合法解,程序就会卡住不终止。
补充优化方案
如果要实现双向查询都可以正常终止的reverso,可以在函数最开头增加两个参数的长度相等约束,提前限制递归深度,避免无限搜索。
内容的提问来源于stack exchange,提问作者tsuki
相关产品推荐
相关产品推荐

