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].