Double elements in list using prolog?

2019-08-03 19:39发布

问题:

How can I double even numbers in a list in Prolog? For example:

X=[1,2,3,5,4]

The result should be:

X=[1,2,2,3,5,4,4]

Thank you!

回答1:

Even check can probably be done better, but it kinda works.

even(N) :- 
    N mod 2 =:= 0.    

doubleeven([],[]).
doubleeven([H|T], [H,H|Z]) :-
    even(H),
    !,
    doubleeven(T,Z).
doubleeven([H|T], [H|Z]) :-
    doubleeven(T,Z).


回答2:

Based on iwhen/2, first define the reified test predicate eveninteger_t/2:

eveninteger_t(I, T) :- 
   iwhen(nonvar(I), ( 0 is I mod 2 -> T = true ; T = false )).

oddinteger_t(I, T) :-   % defined for the sake of completeness
   iwhen(nonvar(I), ( 1 is I mod 2 -> T = true ; T = false )).

Then, in combination with if_/3 define integers_evendups/2 like so:

integers_evendups([], []).
integers_evendups([X|Xs], [X|Zs1]) :-
   if_(evenintegers_t(X), Zs1 = [X|Zs0], Zs1 = Zs0),
   integers_evendups(Xs, Zs0).

Here's the query you gave in your question:

?- Xs = [1,2,3,5,4], integers_evendups(Xs,Zs).
Xs = [1, 2, 3,5, 4 ],
Zs = [1,2,2,3,5,4,4].

Alternative #1

Based on if_//3, define dcg evenintegerdups//1:

evenintegerdups([]) --> 
   [].
evenintegerdups([X|Xs]) -->
   if_(eveninteger_t(X), [X,X], [X]),
   evenintegerdups(Xs).

Alternative #2

Using meta-predicate foldl/4 and lambdas, the code gets even shorter:

:- use_module(library(lambda)).

evenintegerdups(Xs) -->
   foldl(\X^if_(eveninteger_t(X),[X,X],[X]),Xs).


标签: list prolog