Prolog - 在列表中的偶数元素后添加1

时间:2017-10-23 18:06:08

标签: prolog

我开始学习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])等,但我得到的只是虚假,虚假,虚假。请帮忙!

2 个答案:

答案 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