prolog——生成整数“;“不可理解地”;

prolog——生成整数“;“不可理解地”;,prolog,Prolog,我试图用De Bruijn指数定义lambda微积分项。我正在OSX上使用swi prolog 如果我使用自然数的zero |后继者表示,我可以交互式地完成部分指定的项 nat(zero). nat(s(X)) :- nat(X). debruijn2(N) :- nat(N). debruijn2(ap(M, N)) :- debruijn2(M), debruijn2(N). debruijn2(lambda(M)) :- debruijn2(M). 例如,Z和X在ap

我试图用De Bruijn指数定义lambda微积分项。我正在OSX上使用swi prolog

如果我使用自然数的
zero |后继者
表示,我可以交互式地完成部分指定的项

nat(zero).
nat(s(X)) :- nat(X).

debruijn2(N)         :- nat(N).
debruijn2(ap(M, N))  :- debruijn2(M), debruijn2(N).
debruijn2(lambda(M)) :- debruijn2(M).
例如,
Z
X
ap(Z,X)
中统一为
0

但是,使用
length
检查数字会产生类型错误,除非
debruijn
的参数只是一个整数

debruijn(N)          :- length(_, N).
debruijn(ap(M, N))   :- debruijn(M), debruijn(N).
debruijn(lambda(M))  :- debruijn(M).
?- debruijn(ap(Z, X)).
ERROR: Type error: `integer' expected, found `ap(_2944,_2946)' (a compound)
ERROR: In:
ERROR:   [10] throw(error(type_error(integer,...),context(...,_3008)))
ERROR:    [8] debruijn(ap(_3036,_3038)) at <...>:2
ERROR:    [7] <user>
ERROR:
ERROR: Note: some frames are missing due to last-call optimization.
ERROR: Re-run your program in debug mode (:- debug.) to get more detail.
   Exception: (8) debruijn(ap(_2362, _2364)) ? creep
查询
debruijn(X)。
成功并且
X
0
相结合

?- debruijn(X).
X = 0 .
但是,查询
debruijn(ap(Z,X))。
失败,就好像
length(u,·)
不可撤销地将其第二个参数约束为整数一样

debruijn(N)          :- length(_, N).
debruijn(ap(M, N))   :- debruijn(M), debruijn(N).
debruijn(lambda(M))  :- debruijn(M).
?- debruijn(ap(Z, X)).
ERROR: Type error: `integer' expected, found `ap(_2944,_2946)' (a compound)
ERROR: In:
ERROR:   [10] throw(error(type_error(integer,...),context(...,_3008)))
ERROR:    [8] debruijn(ap(_3036,_3038)) at <...>:2
ERROR:    [7] <user>
ERROR:
ERROR: Note: some frames are missing due to last-call optimization.
ERROR: Re-run your program in debug mode (:- debug.) to get more detail.
   Exception: (8) debruijn(ap(_2362, _2364)) ? creep
?-debruijn(ap(Z,X))。
错误:类型错误:应为'integer',找到'ap(_2944,_2946)'(复合)
错误:在:
错误:[10]抛出(错误(类型_错误(整数,…),上下文(…,_3008)))
错误:[8]Debrijn(ap(_3036,_3038))位于:2
错误:[7]
错误:
错误:注意:由于上次调用优化,某些帧丢失。
错误:在调试模式(:-debug.)下重新运行程序以获取更多详细信息。
例外情况:(8)Debrijn(ap(_2362,_2364))?爬行

为什么
length/2
会产生类型错误而不是无法应用于参数?

我怀疑这是因为Prolog在搜索过程中试图计算
length/2
谓词。根据,如果第二个参数绑定到非整数,则会引发错误。这不同于简单地不通过检查

您可以使用将失败转换为假谓词:

debruijn(N)          :- catch(length(_, N), _, false).
debruijn(ap(M, N))   :- debruijn(M), debruijn(N).
debruijn(lambda(M))  :- debruijn(M).

但手册上说,从异常中恢复相当缓慢。无论如何,我都不是Prolog专家,所以可能有更好的解决方案。

在SWI Prolog上运行的替代方案,不需要使用对
length/2
catch/3
的昂贵调用:

debruijn(N)         :- simple(N), nat(N).
debruijn(ap(M, N))  :- debruijn(M), debruijn(N).
debruijn(lambda(M)) :- debruijn(M).

nat(0).
nat(I) :-
    nat(1, I).

nat(I, I).
nat(I, J) :-
    I2 is I + 1,
    nat(I2, J).
如果
simple/1
谓词的参数未实例化为复合项,则该谓词将成功。它是一个从未标准化过的遗留谓词,但在某些Prolog系统中仍然可以找到(例如,它是SWI Prolog中的库谓词,是SICStus Prolog中的内置谓词)


与基于
length/2
的解决方案不同的是,使用负数调用
debruijn/1
时的行为可能与用例相关,也可能与用例无关。在这种情况下,此解决方案将进入循环并最终出现错误,但
length/2
将引发异常,
catch/3
包装将转换为失败。

是否有技巧,例如引入额外变量或其他什么,在基本情况下,
debruijn/1
?@GregoryNisbet扩展了我的答案。生成所有debruijn术语看起来是一个相当不平凡的挑战。。。也许这也会导致一个具有改进的终止属性的检查谓词(例如,
debruijn(0)
成功,然后进入无限循环)。。。我考虑过在从N开始倒数到0时,为顶部索引N生成项,每N从0开始递增,但即使如此,每N的项数似乎也是无限的。。。