SWI:半确定行为:random/3 在 call/1 上下文中?
SWI: Semideterminate behavior : random/3 in call/1 context?
这是我对 Prolog 中确定性概念的初步认识:
我也发现这个讨论很有趣:
我想实现更通用的循环结构(表现得像 findall):
(顺便说一句:findall 源代码看起来很奇怪,无法理解这个“$....”是什么意思)。
fact(1,2).
loop(0,_,RV,RV) :- !.
loop(I, Goal, Acc, RV) :- I > 0, NI is I - 1, call(Goal), Goal =.. Lst, last(Lst,Item), writeln(Item), loop(NI, Goal, [Item|Acc], RV).
如您所见,它在一般情况下有效:
?- loop(3,fact(1,R), [], RV).
2
2
2
R = 2,
RV = [2, 2, 2].
又一次在 random/3 上犹豫不决:
?- loop(3,random(1,10,R), [], RV).
9
false.
我希望 samidet 行为仅在当前调用上下文中保持,而不是在递归调用时保持?
(顺便说一句,swi-docs 说 random/3 是 det 而 random_between/3 是 semidet。两者都以同样的方式失败)。
另一方面,如果我直接随机而不是通过 call/1 随机,它会起作用!!!
这是我决定从中提取的代码 'loop'(使用 ugraph 库):
rand_edges(0, _, _, E, E) :- !.
rand_edges(I, RF, RT, E, RV) :- I > 0, NI is I - 1, random(RF,RT,R1), random(RF,RT,R2), rand_edges(NI, RF, RT, [R1-R2|E], RV).
rand_edges(I, RangeFrom, RangeTo, Edges) :- rand_edges(I, RangeFrom, RangeTo, [], Edges).
rand_edges(I, Edges) :- rand_edges(I, 1, 10, [], Edges).
看到它的工作:
?- rand_edges(5,E).
E = [5-5, 9-7, 2-2, 2-7, 3-5].
为什么 random/3 在 call/1 上下文中不起作用?但可以直接调用 ?
顺便说一句,我只是偶然发现 random/3,还有其他谓词的行为类似于 random/3 吗?
据拓:
loop(0,_,RV,RV) :- !.
loop(I, Goal, Acc, RV) :-
I > 0, NI is I - 1, call(Goal), Goal =.. Lst,
%extract the result of the last call in Item, then substitute the last Var with new un-unified Var
reverse(Lst,[Item|T]), reverse([_NewVar|T], NewLst),
NewGoal =.. NewLst, %build a goal with the new-Var
loop(NI, NewGoal, [Item|Acc], RV).
loop(I, Goal, RV) :- loop(I, Goal, [], RV).
?- loop(5, random(1,10,_R), RV).
_R = 7,
RV = [4, 9, 8, 2, 7].
这是因为一旦 random(1,10,R)
的 R
成为基础(绑定到一个值),
不再 R 不能改变。
在 loop(NI, Goal, [Item|Acc], RV)
部分的递归调用中,
Goal
实际上与 random(1,10,9)
匹配,9
无法更改。
您应该将此 9
更改为自由变量。
此代码将按您的预期运行。
loop(0,_,RV,RV) :- !.
loop(I, Goal, Acc, RV) :-
I > 0,
NI is I - 1,
call(Goal),
Goal =.. Lst,
last(Lst,Item),
writeln(Item),
nth1(1, Lst, First),
nth1(2,Lst,Second),
nth1(3,Lst,Third),
Goal2 =.. [First,Second,Third,NewRand],
loop(NI, Goal2, [Item|Acc], RV).
?- loop(5,random(1,10,R),[],RV).
7
9
2
4
2
R = 7,
RV = [2, 4, 2, 9, 7].
这是我对 Prolog 中确定性概念的初步认识:
我也发现这个讨论很有趣:
我想实现更通用的循环结构(表现得像 findall): (顺便说一句:findall 源代码看起来很奇怪,无法理解这个“$....”是什么意思)。
fact(1,2).
loop(0,_,RV,RV) :- !.
loop(I, Goal, Acc, RV) :- I > 0, NI is I - 1, call(Goal), Goal =.. Lst, last(Lst,Item), writeln(Item), loop(NI, Goal, [Item|Acc], RV).
如您所见,它在一般情况下有效:
?- loop(3,fact(1,R), [], RV).
2
2
2
R = 2,
RV = [2, 2, 2].
又一次在 random/3 上犹豫不决:
?- loop(3,random(1,10,R), [], RV).
9
false.
我希望 samidet 行为仅在当前调用上下文中保持,而不是在递归调用时保持? (顺便说一句,swi-docs 说 random/3 是 det 而 random_between/3 是 semidet。两者都以同样的方式失败)。
另一方面,如果我直接随机而不是通过 call/1 随机,它会起作用!!!
这是我决定从中提取的代码 'loop'(使用 ugraph 库):
rand_edges(0, _, _, E, E) :- !.
rand_edges(I, RF, RT, E, RV) :- I > 0, NI is I - 1, random(RF,RT,R1), random(RF,RT,R2), rand_edges(NI, RF, RT, [R1-R2|E], RV).
rand_edges(I, RangeFrom, RangeTo, Edges) :- rand_edges(I, RangeFrom, RangeTo, [], Edges).
rand_edges(I, Edges) :- rand_edges(I, 1, 10, [], Edges).
看到它的工作:
?- rand_edges(5,E).
E = [5-5, 9-7, 2-2, 2-7, 3-5].
为什么 random/3 在 call/1 上下文中不起作用?但可以直接调用 ?
顺便说一句,我只是偶然发现 random/3,还有其他谓词的行为类似于 random/3 吗?
据拓:
loop(0,_,RV,RV) :- !.
loop(I, Goal, Acc, RV) :-
I > 0, NI is I - 1, call(Goal), Goal =.. Lst,
%extract the result of the last call in Item, then substitute the last Var with new un-unified Var
reverse(Lst,[Item|T]), reverse([_NewVar|T], NewLst),
NewGoal =.. NewLst, %build a goal with the new-Var
loop(NI, NewGoal, [Item|Acc], RV).
loop(I, Goal, RV) :- loop(I, Goal, [], RV).
?- loop(5, random(1,10,_R), RV).
_R = 7,
RV = [4, 9, 8, 2, 7].
这是因为一旦 random(1,10,R)
的 R
成为基础(绑定到一个值),
不再 R 不能改变。
在 loop(NI, Goal, [Item|Acc], RV)
部分的递归调用中,
Goal
实际上与 random(1,10,9)
匹配,9
无法更改。
您应该将此 9
更改为自由变量。
此代码将按您的预期运行。
loop(0,_,RV,RV) :- !.
loop(I, Goal, Acc, RV) :-
I > 0,
NI is I - 1,
call(Goal),
Goal =.. Lst,
last(Lst,Item),
writeln(Item),
nth1(1, Lst, First),
nth1(2,Lst,Second),
nth1(3,Lst,Third),
Goal2 =.. [First,Second,Third,NewRand],
loop(NI, Goal2, [Item|Acc], RV).
?- loop(5,random(1,10,R),[],RV).
7
9
2
4
2
R = 7,
RV = [2, 4, 2, 9, 7].