Prolog:如何删除列表中每第二个元素

5

我需要编写一个Prolog程序,以删除列表中的每个第二个元素。应该按照以下方式工作:[1,2,3,4,5,6,7] -> [1,3,5,7]

到目前为止,我只得到了“false”结果。

r([], []). 
r([H|[T1|T]], R) :- del(T1,[H|[T|T2]], R1), r(R1, R).
del(_, [], []). del(X,[X|T],R):- del(_, T, R). del(X,[H|T],[H|R]):- del(X,T,R).

1
你在 r/2 的第二个子句中调用了 del/3,但第二个参数不是一个合适的术语,看起来像是打错了。此外,你接着调用了一个单参数谓词 r,可能本意是要调用双参数的 r/2。顺便说一下,更简洁的写法是 [H,T1|T],可以替代 [H|[T1|T]] - hardmath
6个回答

8
这基本上是Landei在特定Prolog语法中的答案:
r([], []).
r([X], [X]).
r([X,_|Xs], [X|Ys]) :- r(Xs, Ys).

第二个谓词不是必需的。

4

使用foldl/4的替代方案:

fold_step(Item, true:[Item|Tail], false:Tail).
fold_step(_Item, false:Tail, true:Tail).

odd(List, Odd) :-
    foldl(fold_step, List, true:Odd, _:[]).

使用方法:

?- odd([1, 2, 3, 4, 5, 6, 7], Odd).
Odd = [1, 3, 5, 7]

这个想法是遍历列表,同时保持“奇数/偶数”标记并翻转它的值(false -> true,true -> false)。我们还逐渐构建列表,通过添加那些具有“奇数/偶数”标记等于true的元素,并跳过其他元素。


3
好的!不过,你的解释有点不完整:odd/2可以在不同的实例化模式下工作并且也能给出合理的答案!请考虑查询?- odd(Xs,[a,b,c]).的解决方案。 - repeat

3

这个很好的回答由@code_x386提供 使用了foldl/4

让我们只使用一个fold_step/3子句,并使关系更加通用,像这样:

fold_step(X, [X|Xs]+Ys, Ys+Xs).

list_odds_evens(List, Odds, Evens) :-
   foldl(fold_step, List, Odds+Evens, []+[]).

示例查询:

?– list_odds_evens([a,b,c,d,e,f], Odds, Evens).
Evens = [b,d,f], Odds = [a,c,e]
?– list_odds_evens([a,b,c,d,e,f,g], Odds, Evens).
Evens = [b,d,f], Odds = [a,c,e,g]

编辑

为什么不使用少一个从句并且放弃谓词fold_step/3呢? 来拯救!

:- use_module(library(lambda)).

list_odds_evens(List, Odds, Evens) :
   foldl(\X^([X|Xs]+Ys)^(Ys+Xs)^true,List,Odds+Evens,[]+[]).

1
@tas。上述代码就像 https://dev59.com/cmsz5IYBdhLWcg3wJUfJ#8091652 中的 foldl/4 风格 ;) - repeat

2

另一种可能性是使用DCGs,当描述列表时它们通常是值得考虑的:

list_oddindices(L,O) :-
   phrase(oddindices(L),O).  % the list O is described by oddindices//1

oddindices([]) -->           % if L is empty
   [].                       % O is empty as well
oddindices([X]) -->          % if L has just one element
   [X].                      % it's in O
oddindices([O,_E|OEs]) -->   % if L's head consists of at least two elements
   [O],                      % the first is in O
   oddindices(OEs).          % the same holds for the tail

这种解决方案不如使用foldl/4的解决方案优雅,但代码非常易读,同时它解决了OP所描述的任务,而且两种方式都可以实现:

?- list_oddindices([1,2,3,4,5,6,7],O).
O = [1, 3, 5, 7] ;
false.

?- list_oddindices(L,[1,3,5,7]).
L = [1, _G4412, 3, _G4418, 5, _G4424, 7] ;
L = [1, _G4412, 3, _G4418, 5, _G4424, 7, _G4430] ;
false.

1
更多确定性? - false

0
我只需要一个像这样的函数,并采用了更加“数学化”的方法:
odds(Xs, Ys) :- findall(X, (nth1(I,Xs,X), I mod 2 =:= 1), Ys).

这个方法不像其他一些很好的答案那样双向工作,但它简短而精炼。


0

我这里没有Prolog来尝试它,而且我有点生疏,但应该差不多是这样的

r([]) :- [].
r([X]) :- [X].
r([X,Y|Z]) :- R=r(Z),[X|R].

[编辑]

当然,pad 是正确的。我的解决方案适用于像 Haskell 或 Erlang 这样的函数式编程语言:

--Haskell
r [] = []
r [x] = [x]
r (x:_:xs) = x : (r xs)

在Prolog中,您必须将正确的侧面拉入参数列表以触发统一。

3
Haskell 代码没问题,但是你的 Prolog 代码有误。这个问题标记的是 [tag:prolog] 而不是 [tag:haskell]。糟糕! - repeat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接