[英]Fill list in SWI-Prolog
我正在嘗試用數字 1、2、3、...、N 填充給定長度 N 的列表。
我認為這可以這樣做:
create_list(N,L) :-
length(L,N),
forall(between(1,N,X), nth1(X,L,X)).
但是,這似乎不起作用。 誰能說我做錯了什么?
這是使用clpfd的謂詞zs_from_to/3
的邏輯純實現:
:- use_module(library(clpfd)).
zs_from_to([],I0,I) :-
I0 #> I.
zs_from_to([I0|Is],I0,I) :-
I0 #=< I,
I1 #= I0 + 1,
zs_from_to(Is,I1,I).
讓我們使用它,首先,一些地面查詢:
?- zs_from_to([1,2,3],1,3). true. ?- zs_from_to([1,2,3],1,4). false.
接下來,一些更一般的查詢:
?- zs_from_to(Zs,1,7).
Zs = [1,2,3,4,5,6,7]
; false.
?- zs_from_to([1,2,3],From,To).
From = 1, To = 3.
現在,讓我們進行一些更一般的查詢:
?- zs_from_to(Zs,From,2).
Zs = [], From in 3..sup
; Zs = [2], From = 2
; Zs = [1,2], From = 1
; Zs = [0,1,2], From = 0
; Zs = [-1,0,1,2], From = -1
; Zs = [-2,-1,0,1,2], From = -2
...
?- zs_from_to(Zs,0,To).
Zs = [], To in inf.. -1
; Zs = [0], To = 0
; Zs = [0,1], To = 1
; Zs = [0,1,2], To = 2
; Zs = [0,1,2,3], To = 3
; Zs = [0,1,2,3,4], To = 4
...
對於最一般的查詢,我們得到什么答案?
?- zs_from_to(Xs,I,J).
Xs = [], J#=<I+ -1
; Xs = [I], I+1#=_A, J#>=I, J#=<_A+ -1
; Xs = [I,_A], I+1#=_A, J#>=I, _A+1#=_B, J#>=_A, J#=<_B+ -1
; Xs = [I,_A,_B], I+1#=_A, J#>=I, _A+1#=_B, J#>=_A, _B+1#=_C, J#>=_B, J#=<_C+ -1
...
為了改進zs_from_to/3
的上述實現,讓我們做兩件事:
zs_from_to/3
。 介紹元謂詞init0/3
和init1/3
:
:- meta_predicate init0(2,?,?).
:- meta_predicate init1(2,?,?).
init0(P_2,Expr,Xs) :- N is Expr, length(Xs,N), init_aux(Xs,P_2,0).
init1(P_2,Expr,Xs) :- N is Expr, length(Xs,N), init_aux(Xs,P_2,1).
:- meta_predicate init_aux(?,2,+). % internal auxiliary predicate
init_aux([] , _ ,_ ).
init_aux([Z|Zs],P_2,I0) :-
call(P_2,I0,Z),
I1 is I0+1,
init_aux(Zs,P_2,I1).
讓我們看看init0/3
和init1/3
的作用!
?- init0(=,5,Zs). % ?- numlist(0,4,Xs),maplist(=,Xs,Zs). Zs = [0,1,2,3,4]. ?- init1(=,5,Zs). % ?- numlist(1,5,Xs),maplist(=,Xs,Zs). Zs = [1,2,3,4,5].
好的,我們從這里到哪里 go? 考慮以下查詢:
?- init0(plus(10),5,Zs). % ?- numlist(0,4,Xs),maplist(plus(10),Xs,Zs). Zs = [10,11,12,13,14].
差不多完成了,把它放在一起,我們定義zs_from_to/2
像這樣:
z_z_sum(A,B,C) :- C #= A+B.
zs_from_to(Zs,I0,I) :-
N #= I-I0+1,
init0(z_z_sum(I0),N,Zs).
最后,讓我們看看確定性是否有所改進!
?- zs_from_to(Zs,1,7).
Zs = [1,2,3,4,5,6,7]. % succeeds deterministically
首先要做的事情:使用clpfd !
:- use_module(library(clpfd)).
下面我介紹zs_between_and/3
,它(與我之前的答案相比)提供了更多功能。
首先,讓我們先定義一些輔助謂詞!
equidistant_stride([] ,_).
equidistant_stride([Z|Zs],D) :-
equidistant_prev_stride(Zs,Z,D).
equidistant_prev_stride([] ,_ ,_). % internal predicate
equidistant_prev_stride([Z1|Zs],Z0,D) :-
Z1 #= Z0+D,
equidistant_prev_stride(Zs,Z1,D).
讓我們運行一些查詢來獲取equidistant_stride/2
的圖片:
?- Zs = [_,_,_], equidistant_stride(Zs,D).
Zs = [_A,_B,_C], _A+D#=_B, _B+D#=_C.
?- Zs = [1,_,_], equidistant_stride(Zs,D).
Zs = [1,_B,_C], _B+D#=_C, 1+D#=_B.
?- Zs = [1,_,_], equidistant_stride(Zs,10).
Zs = [1,11,21].
到目前為止,一切都很好......繼續實際的“填充列表”謂詞zs_between_and/3
:
zs_between_and([Z0|Zs],Z0,Z1) :-
Step in -1..1,
Z0 #= Z1 #<==> Step #= 0,
Z0 #< Z1 #<==> Step #= 1,
Z0 #> Z1 #<==> Step #= -1,
N #= abs(Z1-Z0),
( fd_size(N,sup)
-> true
; labeling([enum,up],[N])
),
length(Zs,N),
labeling([enum,down],[Step]),
equidistant_prev_stride(Zs,Z0,Step).
有點巴洛克風格,我必須承認...
讓我們看看獲得了哪些功能——與我之前的答案相比!
?- zs_between_and(Zs,1,4). % ascending consecutive integers
Zs = [1,2,3,4]. % (succeeds deterministically)
?- zs_between_and(Zs,3,1). % descending consecutive integers (NEW)
Zs = [3,2,1]. % (succeeds deterministically)
?- zs_between_and(Zs,L,10). % enumerates fairly
L = 10, Zs = [10] % both ascending and descenting (NEW)
; L = 9, Zs = [9,10]
; L = 11, Zs = [11,10]
; L = 8, Zs = [8,9,10]
; L = 12, Zs = [12,11,10]
; L = 7, Zs = [7,8,9,10]
...
?- L in 1..3, zs_between_and(Zs,L,6).
L = 3, Zs = [3,4,5,6]
; L = 2, Zs = [2,3,4,5,6]
; L = 1, Zs = [1,2,3,4,5,6].
想要更多? 開始了!
?- zs_between_and([1,2,3],From,To).
From = 1, To = 3
; false.
?- zs_between_and([A,2,C],From,To).
A = 1, From = 1, C = 3, To = 3 % ascending
; A = 3, From = 3, C = 1, To = 1. % descending
如果我理解正確,內置謂詞 numlist/3 就可以了。 http://www.swi-prolog.org/pldoc/man?predicate=numlist/3
我現在沒有可用的 prolog 解釋器,但不會像...
isListTo(N, L) :- reverse(R, L), isListFrom(N, R).
isListFrom(0, []).
isListFrom(N, [H|T]) :- M is N - 1, N is H, isListFrom(M, T).
可以通過使用例如http://www.webeks.net/prolog/prolog-reverse-list-function.html來完成反向
所以追蹤 isListTo(5, [1, 2, 3, 4, 5])...
isListTo(5, [1, 2, 3, 4, 5])
<=> isListFrom(5, [5, 4, 3, 2, 1])
<=> 5 is 5 and isListFrom(4, [4, 3, 2, 1])
<=> 4 is 4 and isListFrom(3, [3, 2, 1])
<=> 3 is 3 and isListFrom(2, [2, 1])
<=> 2 is 2 and isListFrom(1, [1])
<=> 1 is 1 and isListFrom(0, [])
QED
由於 PROLOG 不僅會評估真相,還會找到令人滿意的解決方案,這應該可以工作。 我知道這是一種與您正在嘗試的方法截然不同的方法,如果您的問題是專門關於在 PROLOG 中執行循環的問題(如果是這種情況,也許重新標記問題?)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.