我开始学习prolog。我想在列表中的每个偶数后添加1。这是我的代码:
member(E,[E|_]).
member(E,[_|T]):-
member(E,T).
add([],[]).
add([H|T],[H|[1|T1]]):-
H mod 2=0,!,
add(T,T1).
add([H|T],[H|T1]):-
add(T,T1).
我尝试添加([5,6,7],[5,6,1,7]),添加([5,6,7],[5,1,6,7])等,但我得到的只是虚假,虚假,虚假。请帮忙!
答案 0 :(得分:3)
您也可以选择使用DCG来描述此类列表。请考虑以下代码:
:- use_module(library(clpfd)).
list_inserted(L,I) :-
phrase(inserted(L),I). % the DCG inserted//1 describes I based on L
inserted([]) --> % if L is empty
[]. % I is empty
inserted([X|Xs]) --> % if the head of the list L
{X mod 2 #= 0}, % is even
[X,1], % it's in the list I followed by 1
inserted(Xs). % the same holds for the tail
inserted([X|Xs]) --> % if the head of the list L
{X mod 2 #= 1}, % is odd
[X], % it's in the list I
inserted(Xs). % the same holds for the tail
如果使用您的示例查询此谓词,则会产生所需的结果:
?- list_inserted([5,6,7],I).
I = [5, 6, 1, 7] ;
谓词也适用于另一个方向:
?- list_inserted(L,[5,6,1,7]).
L = [5, 6, 7] ;
false.
?- list_inserted(L,[5,1,7]).
L = [5, 1, 7] ;
false.
但是,最常见的查询是以不公平的方式列出解决方案:首先列出仅包含偶数元素的列表。由于有无数的这些,你永远不会看到包含奇数元素的列表:
?- list_inserted(L,I).
L = I, I = [] ;
L = [_G762], % <- [even]
I = [_G762, 1],
_G762 mod 2#=0 ;
L = [_G847, _G850], % <- [even,even]
I = [_G847, 1, _G850, 1],
_G847 mod 2#=0,
_G850 mod 2#=0 ;
L = [_G932, _G935, _G938], % <- [even,even,even]
I = [_G932, 1, _G935, 1, _G938, 1],
_G932 mod 2#=0,
_G935 mod 2#=0,
_G938 mod 2#=0 .
.
.
.
您可以通过为目标长度/ 2添加前缀来改进。这种方式对于每个列表长度,生成奇数和偶数元素的所有可能组合:
?- length(L,_), list_inserted(L,I).
L = I, I = [] ;
L = [_G65], % <- [even]
I = [_G65, 1],
_G65 mod 2#=0 ;
L = I, I = [_G180], % <- [odd]
_G180 mod 2#=1 ;
L = [_G110, _G113], % <- [even,even]
I = [_G110, 1, _G113, 1],
_G110 mod 2#=0,
_G113 mod 2#=0 ;
L = [_G228, _G231], % <- [even,odd]
I = [_G228, 1, _G231],
_G228 mod 2#=0,
_G231 mod 2#=1 ;
L = [_G265, _G268], % <- [odd,even]
I = [_G265, _G268, 1],
_G265 mod 2#=1,
_G268 mod 2#=0 ;
L = I, I = [_G262, _G265], % <- [odd,odd]
_G262 mod 2#=1,
_G265 mod 2#=1 ;
.
.
.
答案 1 :(得分:2)
主要问题是:
0 mod 2 = 0
是false
。实际上,由于0 mod 2
实际上是mod(0,2)
的缩写,mod(0,2)
在Prolog中不等于0
(除非您评估 {{1 }})。您可以使用mod(0,2)
谓词对其进行评估。所以快速解决方法是:
is/2
现在以某种方式在多个方向上工作:
add([],[]).
add([H|T],[H|[1|T1]]):-
0 is H mod 2,
!,
add(T,T1).
add([H|T],[H|T1]):-
add(T,T1).
但这仍然不是一个好主意:你使用剪切(?- add([5,6,7],[5,6,1,7]).
true.
?- add([5,6,7],L).
L = [5, 6, 1, 7].
?- add(L,[5,6,1,7]).
L = [5, 6, 7].
)。切割的问题通常是统一的另一个方向可能是有问题的。此外,如果列表中的元素未被接地,这意味着如果您给它!
,它将引发异常。此外想象一下,如果你进行验证,并且第二个列表是基础列表,但是使用模式add([1,2,X,4],L).
,Prolog将跳过该子句,从而导致采用最后一个子句,即不预期的行为。我们可以用第二个条款的警卫重写它:
[H|[1|T]]
但这仍然不是很优雅:因为它需要add([],[]).
add([H|T],[H|[1|T1]]):-
0 is H mod 2,
add(T,T1).
add([H|T],[H|T1]) :-
\+ 0 is H mod 2,
add(T,T1).
作为接地号码,否则会引发异常。
我们可以使用 C onstraint L ogic P 编程库而不是 F inite D < / strong> omains for this:
H