确定逻辑程序
Definite Logic Program
目的是实现谓词noDupl/2
。
该谓词的第一个参数是要分析的列表,第二个参数是不重复的数字列表。
我无法理解下面的代码,当我编译它时,它给出了一条错误消息,指出 contained
是未定义的过程,但是作为提示,我们可以将其用作预定义谓词 contained
和 notContained
。我想我需要定义 contained
和 notContained
.
noDupl(XS, Res):-
help( XS, [],Res).
help([],_,[]).
help([X|XS],Seen,[X|Res]):-
notContained(X,XS),
notContained(X,Seen),
help(XS, [X|Seen], Res).
help([X|XS],Seen,Res):-
contained(X,Seen),
help(XS, Seen, Res).
help([X|XS],Seen,Res):-
contained(X,XS),
help(XS, [X|Seen], Res).
谁能解释一下这个问题。
缺少的定义可能是:
contained(X,[X|_]).
contained(X,[E|Es]) :-
dif(X, E),
contained(X, Es).
notContained(_X, []).
notContained(X, [E|Es]) :-
dif(X, E),
notContained(X, Es).
(我喜欢称这些关系为 memberd/2
和 non_member/2
。)
您给出的定义扩展了关系,为目前考虑的元素增加了一个额外的参数。
要理解每个子句的含义,请按箭头方向从右到左阅读每个子句(:-
是 1970 年代 ←
的 ASCII 化)。让我们来看第一个规则:
Provided, that X
is not an element of XS
, and
provided, that X
is not an element of Seen
, and
provided, that help(X, [X|Seen], Res)
is true,
then also help([X|XS],Seen,[X|Res])
is true.
换句话说,如果X
既不在已访问元素列表Seen
中,也不在尚未访问的元素列表XS
中,则它不具有重复项。
有点难以理解的是你给出的子句是否互斥 - 严格来说,这不是你关心的,只要你只对声明性属性感兴趣,但这是一个很好的避免这种冗余的想法。
这是一个案例,其中显示了这种冗余:
?- noDupl([a,a,a],U).
U = [] ;
U = [] ;
false.
理想情况下,系统会给出一个确定的答案:
?- noDupl([a,a,a], U).
U = [].
就个人而言,我不太喜欢把事情分成太多的情况。本质上,我们可以有两个:它是一个副本,它是 none.
可以提供一个正确的定义,并且对于确定性可能存在的情况仍然完全确定 - 例如当第一个参数是 "sufficiently instantiated"(其中包括一个基本列表)时。让我们看看这个方向是否有一些答案。
我已经为你注释了你的代码:
noDupl( XS , Res ) :- % Res is the [unique] set of element from the bag XS
help( XS, [],Res) % if invoking the helper succeeds.
. %
help( [] , _ , [] ) . % the empty list is unique.
help( [X|XS] , Seen , [X|Res] ) :- % A non-empty list is unique, if...
notContained(X,XS), % - its head (X) is not contained in its tail (XS), and
notContained(X,Seen), % - X has not already been seen, and
help(XS, [X|Seen], Res). % - the remainder of the list is unique.
help( [X|XS] , Seen , Res ) :- % otherwise...
contained(X,Seen) , % - if X has been seen,
help(XS, Seen, Res). % - we discard it and recurse down on the tail.
help([X|XS],Seen,Res):- % otherwise...
contained(X,XS), % - if X is in the tail of the source list,
help(XS, [X|Seen], Res). % - we discard it (but add it to 'seen').
您的 contained/2
和 notContained/2` 谓词可能定义为:
contained( X , [X|_] ) :- ! .
contained( X , [Y|Ys] ) :- X \= Y , contained( X , Ys ) .
not_contained( _ , [] ) .
not_contained( X , [Y|Ys] ) :- X \= Y , not_contained(X,Ys) .
现在,我可能在您的代码中遗漏了一些东西,但其中有很多冗余。你可以简单地写这样的东西(使用内置的 member/2
和 reverse/2
):
no_dupes( List , Unique ) :- no_dupes( Bag , [] , Set ) .
no_dupes( [] , V , S ) . % if we've exhausted the bag, the list of visited items is our set (in reverse order of the source)
reverse(V,S) % - reverset it
. % - to put our set in source order
no_dupes( [X|Xs] , V , S ) :- % otherwise ...
( member(X,V) -> % - if X is already in the set,
V1 = V % - then we discard X
; V1 = [X|V] % - else we add X to the set
) , % And...
no_dupes( Xs , V1 , S ) % we recurse down on the remainder
. % Easy!
能否以纯粹高效的方式完成?
是,通过使用
tpartition/4
and (=)/3
像这样:
dups_gone([] ,[]).
dups_gone([X|Xs],Zs0) :-
tpartition(=(X),Xs,Ts,Fs),
if_(Ts=[], Zs0=[X|Zs], Zs0=Zs),
dups_gone(Fs,Zs).
一些示例地面查询(所有这些都确定性地成功):
?- dups_gone([a,a,a],Xs).
Xs = [].
?- dups_gone([a,b,c],Xs).
Xs = [a, b, c].
?- dups_gone([a,b,c,b],Xs).
Xs = [a, c].
?- dups_gone([a,b,c,b,a],Xs).
Xs = [c].
?- dups_gone([a,b,c,b,a,a,a],Xs).
Xs = [c].
?- dups_gone([a,b,c,b,a,a,a,c],Xs).
Xs = [].
这也适用于更一般的查询。考虑:
?- length(Xs,N), dups_gone(Xs,Zs).
N = 0, Xs = [], Zs = []
; N = 1, Xs = [_A], Zs = [_A]
; N = 2, Xs = [_A,_A], Zs = []
; N = 2, Xs = [_A,_B], Zs = [_A,_B], dif(_A,_B)
; N = 3, Xs = [_A,_A,_A], Zs = []
; N = 3, Xs = [_A,_A,_B], Zs = [_B], dif(_A,_B)
; N = 3, Xs = [_A,_B,_A], Zs = [_B], dif(_A,_B)
; N = 3, Xs = [_B,_A,_A], Zs = [_B], dif(_A,_B), dif(_A,_B)
; N = 3, Xs = [_A,_B,_C], Zs = [_A,_B,_C], dif(_A,_B), dif(_A,_C), dif(_B,_C)
; N = 4, Xs = [_A,_A,_A,_A], Zs = []
...
目的是实现谓词noDupl/2
。
该谓词的第一个参数是要分析的列表,第二个参数是不重复的数字列表。
我无法理解下面的代码,当我编译它时,它给出了一条错误消息,指出 contained
是未定义的过程,但是作为提示,我们可以将其用作预定义谓词 contained
和 notContained
。我想我需要定义 contained
和 notContained
.
noDupl(XS, Res):-
help( XS, [],Res).
help([],_,[]).
help([X|XS],Seen,[X|Res]):-
notContained(X,XS),
notContained(X,Seen),
help(XS, [X|Seen], Res).
help([X|XS],Seen,Res):-
contained(X,Seen),
help(XS, Seen, Res).
help([X|XS],Seen,Res):-
contained(X,XS),
help(XS, [X|Seen], Res).
谁能解释一下这个问题。
缺少的定义可能是:
contained(X,[X|_]).
contained(X,[E|Es]) :-
dif(X, E),
contained(X, Es).
notContained(_X, []).
notContained(X, [E|Es]) :-
dif(X, E),
notContained(X, Es).
(我喜欢称这些关系为 memberd/2
和 non_member/2
。)
您给出的定义扩展了关系,为目前考虑的元素增加了一个额外的参数。
要理解每个子句的含义,请按箭头方向从右到左阅读每个子句(:-
是 1970 年代 ←
的 ASCII 化)。让我们来看第一个规则:
Provided, that
X
is not an element ofXS
, and
provided, thatX
is not an element ofSeen
, and
provided, thathelp(X, [X|Seen], Res)
is true,
then alsohelp([X|XS],Seen,[X|Res])
is true.
换句话说,如果X
既不在已访问元素列表Seen
中,也不在尚未访问的元素列表XS
中,则它不具有重复项。
有点难以理解的是你给出的子句是否互斥 - 严格来说,这不是你关心的,只要你只对声明性属性感兴趣,但这是一个很好的避免这种冗余的想法。
这是一个案例,其中显示了这种冗余:
?- noDupl([a,a,a],U).
U = [] ;
U = [] ;
false.
理想情况下,系统会给出一个确定的答案:
?- noDupl([a,a,a], U).
U = [].
就个人而言,我不太喜欢把事情分成太多的情况。本质上,我们可以有两个:它是一个副本,它是 none.
可以提供一个正确的定义,并且对于确定性可能存在的情况仍然完全确定 - 例如当第一个参数是 "sufficiently instantiated"(其中包括一个基本列表)时。让我们看看这个方向是否有一些答案。
我已经为你注释了你的代码:
noDupl( XS , Res ) :- % Res is the [unique] set of element from the bag XS
help( XS, [],Res) % if invoking the helper succeeds.
. %
help( [] , _ , [] ) . % the empty list is unique.
help( [X|XS] , Seen , [X|Res] ) :- % A non-empty list is unique, if...
notContained(X,XS), % - its head (X) is not contained in its tail (XS), and
notContained(X,Seen), % - X has not already been seen, and
help(XS, [X|Seen], Res). % - the remainder of the list is unique.
help( [X|XS] , Seen , Res ) :- % otherwise...
contained(X,Seen) , % - if X has been seen,
help(XS, Seen, Res). % - we discard it and recurse down on the tail.
help([X|XS],Seen,Res):- % otherwise...
contained(X,XS), % - if X is in the tail of the source list,
help(XS, [X|Seen], Res). % - we discard it (but add it to 'seen').
您的 contained/2
和 notContained/2` 谓词可能定义为:
contained( X , [X|_] ) :- ! .
contained( X , [Y|Ys] ) :- X \= Y , contained( X , Ys ) .
not_contained( _ , [] ) .
not_contained( X , [Y|Ys] ) :- X \= Y , not_contained(X,Ys) .
现在,我可能在您的代码中遗漏了一些东西,但其中有很多冗余。你可以简单地写这样的东西(使用内置的 member/2
和 reverse/2
):
no_dupes( List , Unique ) :- no_dupes( Bag , [] , Set ) .
no_dupes( [] , V , S ) . % if we've exhausted the bag, the list of visited items is our set (in reverse order of the source)
reverse(V,S) % - reverset it
. % - to put our set in source order
no_dupes( [X|Xs] , V , S ) :- % otherwise ...
( member(X,V) -> % - if X is already in the set,
V1 = V % - then we discard X
; V1 = [X|V] % - else we add X to the set
) , % And...
no_dupes( Xs , V1 , S ) % we recurse down on the remainder
. % Easy!
能否以纯粹高效的方式完成?
是,通过使用
tpartition/4
and (=)/3
像这样:
dups_gone([] ,[]).
dups_gone([X|Xs],Zs0) :-
tpartition(=(X),Xs,Ts,Fs),
if_(Ts=[], Zs0=[X|Zs], Zs0=Zs),
dups_gone(Fs,Zs).
一些示例地面查询(所有这些都确定性地成功):
?- dups_gone([a,a,a],Xs).
Xs = [].
?- dups_gone([a,b,c],Xs).
Xs = [a, b, c].
?- dups_gone([a,b,c,b],Xs).
Xs = [a, c].
?- dups_gone([a,b,c,b,a],Xs).
Xs = [c].
?- dups_gone([a,b,c,b,a,a,a],Xs).
Xs = [c].
?- dups_gone([a,b,c,b,a,a,a,c],Xs).
Xs = [].
这也适用于更一般的查询。考虑:
?- length(Xs,N), dups_gone(Xs,Zs).
N = 0, Xs = [], Zs = []
; N = 1, Xs = [_A], Zs = [_A]
; N = 2, Xs = [_A,_A], Zs = []
; N = 2, Xs = [_A,_B], Zs = [_A,_B], dif(_A,_B)
; N = 3, Xs = [_A,_A,_A], Zs = []
; N = 3, Xs = [_A,_A,_B], Zs = [_B], dif(_A,_B)
; N = 3, Xs = [_A,_B,_A], Zs = [_B], dif(_A,_B)
; N = 3, Xs = [_B,_A,_A], Zs = [_B], dif(_A,_B), dif(_A,_B)
; N = 3, Xs = [_A,_B,_C], Zs = [_A,_B,_C], dif(_A,_B), dif(_A,_C), dif(_B,_C)
; N = 4, Xs = [_A,_A,_A,_A], Zs = []
...