[英]Prolog: compare list elements and sum
Prolog的新增功能,並嘗試實現以下包含3個列表的功能:
示例: fn([1,2,3],[4,5,6],[5,7,9])
返回true
。 注意,總和是逐元素加法。
這是我到目前為止的內容:
fn([],[],[]).
fn([_|T1], [_|T2], [_|T3]) :-
fn(T1,T2,T3), % check they are same length
fn(T1,T2,N1), % check that T3=T1+T2
N1 is T1+T2,
N1 = T3.
據我了解,該錯誤是由於基本情況造成的(它具有空列表,這會導致加法評估出錯?)
感謝您的幫助和解釋!
除了@GuyCoder的答案,我還指出,在修改列表的所有元素時,值得考慮使用來自library(apply)的maplist謂詞之一。 您可以使用謂詞來描述三個數字之間的關系...
:- use_module(library(apply)). % for maplist/4
num_num_sum(X,Y,S) :-
S is X+Y.
...,然后使用maplist / 4將其應用於整個列表:
fn(X,Y,Z) :-
maplist(num_num_sum,X,Y,Z).
如果前兩個列表被完全實例化,則該謂詞將產生所需的結果:
?- fn([1,2,3],[4,5,6],X).
X = [5,7,9]
但是,由於使用了is / 2,如果前兩個列表包含變量,則會出現實例化錯誤:
?- fn([1,A,3],[4,5,6],[5,7,9]).
ERROR at clause 1 of user:num_num_sum/3 !!
INSTANTIATION ERROR- X is _+B: expected bound value
?- fn([1,2,3],[4,5,A],[5,7,9]).
ERROR at clause 1 of user:num_num_sum/3 !!
INSTANTIATION ERROR- X is A+B: expected bound value
如果只想對整數列表使用謂詞,則可以使用CLP(FD)使謂詞更通用:
:- use_module(library(apply)).
:- use_module(library(clpfd)). % <- use CLP(FD)
int_int_sum(X,Y,S) :-
S #= X+Y. % use CLP(FD) constraint #=/2 instead of is/2
fnCLP(X,Y,Z) :-
maplist(int_int_sum,X,Y,Z).
有了這個定義,以前有問題的查詢也可以工作:
?- fnCLP([1,A,3],[4,5,6],[5,7,9]).
A = 2
?- fnCLP([1,2,3],[4,5,A],[5,7,9]).
A = 6
即使是最一般的查詢,使用此版本也會產生結果:
?- fnCLP(X,Y,Z).
X = Y = Z = [] ? ;
X = [_A],
Y = [_B],
Z = [_C],
_A+_B#=_C ? ;
X = [_A,_B],
Y = [_C,_D],
Z = [_E,_F],
_A+_C#=_E,
_B+_D#=_F ? ;
.
.
.
由於上述答案中的數字不是唯一確定的,因此您將獲得剩余目標而不是實際數字。 為了獲得答案中的實際數字,您必須限制兩個列表的范圍並對其進行標記(請參閱文檔以獲取詳細信息),例如,生成包含第一個列表中的數字3、4、5和6的列表。 ,7,8在第二個列表中,您可以查詢:
label the lists
restrict the domain | |
v v v v
?- fnCLP(X,Y,Z), X ins 3..5, Y ins 6..8, label(X), label(Y).
X = Y = Z = [] ? ;
X = [3],
Y = [6],
Z = [9] ? ;
X = [3],
Y = [7],
Z = [10] ? ;
.
.
.
X = [3,4],
Y = [6,7],
Z = [9,11] ? ;
X = [3,4],
Y = [6,8],
Z = [9,12] ? ;
.
.
.
據我了解,該錯誤是由於基本情況造成的。
我不這樣認為。
我看到的第一個問題是,您正在嘗試處理導致使用DCG的列表,但是由於您是新手,所以我會避免使用該方法。
在處理列表時,通常會處理列表的頭部,然后使用遞歸將尾部傳遞回謂詞。
例如,對於列表長度
ln([],N,N).
ln([_|T],N0,N) :-
N1 is N0+1,
ln(T,N1,N).
ln(L,N) :-
ln(L,0,N).
謂詞ln/2
用於將初始計數設置為0,而謂詞ln/3
使用遞歸進行工作。 請注意,列表的開頭如何從列表的前面移開,列表的結尾如何又遞歸地傳遞到謂詞上。 當列表為空時,謂詞ln([],N,N).
在這種情況下,請考慮將副本從第二個位置轉換為第三個位置的中間計數,然后將其與ln/2
一起傳回。
現在回到您的問題。
基本情況很好
fn([],[],[]).
一共有三個列表,每個列表都以[H|T]
fn([H1|T1],[H2|T2],[H3|T3])
而在尾部進行遞歸的調用是
fn(T1,T2,T3)
剩下的就是處理頭部
H3 is H1 + H2
放在一起給我們
fn([],[],[]).
fn([H1|T1], [H2|T2], [H3|T3]) :-
H3 is H1 + H2,
fn(T1,T2,T3).
和快速檢查。
?- fn([],[],[]).
true.
?- fn([1],[1],[2]).
true.
?- fn([1,2],[3,4],[4,6]).
true.
?- fn([1,2],[3,4,5],[4,6,5]).
false.
關於這兩個條件。 當我查看邏輯編程的練習題時, True if lists are the same length
或返回true的其他條件,則有時會給出諸如True if lists are the same length
條件。 我傾向於一開始就忽略這些內容,而是專注於首先完成另一部分,在這種情況下elements of third list is sum of the two lists
然后檢查其他條件是否正確。 對於大多數簡單的課堂練習,它們都是如此。 我有時認為老師會嘗試給出這些額外的條件來使學生感到困惑,但實際上,僅僅是為了闡明代碼應如何工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.