Prolog-从子列表中删除元素



问题陈述:你会得到一个包含整数和整数列表的列表。您必须删除从每个子列表中,第1个、第2个、第4个、第8个。。等等元素。

我的解决方案

domains
        list=integer*
        elem=i(integer);l(list)
        clist=elem*
predicates
        modify(list, list, integer, integer)
        exec(clist, clist)
clauses
        modify([], [], _, _).
        modify([H|T], Mod, I, P):-
                P=I,
                !,
                I1=I+1,
                P1=P*2,
                modify(T, Mod, I1, P1).
        modify([H,T], [H|Mod], I, P):-
                I1=I+1,
                modify(T, Mod, I1, P).
        exec([], []).
        exec([i(N)|T], [i(N)|LR]):-
                exec(T, LR).
        exec([l(L)|T], [l(Mod)|LR]):-
                modify(L, Mod, 1, 1).
        do():-
                exec([i(1),l([1,2,3,4,5,6,7,8,9]),l([1,2,3,4])],X),
                write(X).

问题是,该算法一直有效,直到它从每个子列表中删除了第一个和第二个元素,但从那时起,它不会删除任何东西,我不确定我做错了什么。

exec predicate用于断言当前元素是整数还是整数列表,将整数添加到结果,或将修改后的列表添加到结果。

CCD_ 2修改给定列表并且应当移除位置幂为2的所有元素。

我写do predicate只是为了把它作为一个目标,以避免每次我想测试它时都写列表。

我认为你做P1=P*2太频繁了,然后你不匹配2个的连续幂

另外,你在这里有一个打字错误

modify([H,T], [H|Mod], I, P):- ...

应读取

modify([H|T], [H|Mod], I, P):- ...

我会写

modify([], [], _).
modify([_|T], Mod, I):-
    is_pow2(I), !, % as noted by SQB
    I1 is I+1,
    modify(T, Mod, I1).
modify([H|T], [H|Mod], I):-
    I1 is I+1,
    modify(T, Mod, I1).

为了保持is_pow2/1的简单性,您可以进行

is_pow2(1).
is_pow2(2).
is_pow2(4).
is_pow2(8).
is_pow2(16).
...

或者使用Prolog算术工具。在SWI Prolog中,一个简单的定义可以是

is_pow2(N) :- 
    between(0, 63, L),
    N is 1 << L.

实际上,修改的核心是正确的,所以它可能是exec中的一个问题。以下对我有效:

do_modify(X) :-
  modify([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18], X, 2).
modify(Lin, Lout, Base) :- modify(Lin, Lout, Base, 1, 1).
modify([], [], _, _, _).
modify([_|T], X, Base, N, Power) :-
  N = Power,
  !,
  P1 is Power * Base,
  N1 is N + 1,
  modify(T, X, Base, N1, P1).
modify([H|T], [H|X], Base, N, Power) :-
  N1 is N + 1,
  modify(T, X, Base, N1, Power).

在上进行了测试http://www.compileonline.com/execute_prolog_online.php.

最新更新