Prolog列表和递归

时间:2011-04-22 08:13:08

标签: list recursion prolog

我在理解Prolog中的人为递归方面遇到了问题。

一些辅助谓词分别只附加到开头和结尾:

add_number(Numbers, N, NewNumbers).
add_letter(Letters, L, NewLetters).

我的目标是获取一个字母和数字列表并返回两个列表:按出现顺序排列的数字列表,加1;以及出现相反顺序的字母列表。这是我的理由:

foo([], [], [], [], []).

foo([X|Xs], Nums, NewNums, Letters, Letters) :-
    number(X),
    X1 is X+1,
    add_number(Nums, X1, NewNums),
    foo(Xs, ???, ???, Letters, Letters).

foo([X|Xs], Nums, Nums, Letters, NewLetters) :-
    letter(X),
    add_letter(Letters, X, NewLetters),
    foo(Xs, Nums, Nums, ???, ???).

第二个和第四个参数是累加器。

然后它应该像这样调用:

realfoo(Xs, Nums, Letters) :- foo(Xs, [], Nums, [], Letters).

如何编写此代码?

3 个答案:

答案 0 :(得分:1)

使用累加器以相反的顺序构建列表。不要使用add_number或者你会得到二次时间算法,而你可以在线性时间内解决这个问题。

foo([], NumsR, Nums, Letters, Letters) :-
    reverse(NumsR, Nums).
foo([X|Xs], NumsR, Nums, LettersR, Letters) :-
    % the following is the Prolog syntax for if-then-else;
    % you could also do this with two recursive clauses,
    % but this option is faster because of first-argument indexing
    (number(X) ->
        X1 is X+1,
        foo(Xs, [X1|NumsR], Nums, LettersR, Letters)
    ;
        foo(Xs, NumsR, Nums, [X|LettersR], Letters)
    ).

答案 1 :(得分:0)

foo([],Nums,Nums,Letters,Letters)。

foo([X | Xs],Nums_1,Nums,Letters_1,Letters): -     数(X),     X1是X + 1,     add_number(Nums_1,X1,Nums_2),     foo(Xs,Nums_2,Nums,Letters_1,Letters)。

foo([X | Xs],Nums_1,Nums,Letters_1,Letters): -     信(X),     add_letter(Letters_1,X,Letters_2),     foo(Xs,Nums_1,Nums,Letters_2,Letters)。

add_number(Nums_1,X,Nums_2): -     追加(Numbs_1,[X],nums_2)。

add_letter(Letters_1,X,Letters_2): -     追加(Letters_1,[X],Letters_2)。

答案 2 :(得分:0)

我会这样做:

foo( List , Numbers , Letters ) :-
  worker( List , [] , Numbers , [] , Letters ).

worker( []     , Numbers           , Numbers , Letters           , Letters ).
worker( [X|Xs] , NumberAccumulator , Numbers , LetterAccumulator , Letters ) :-
  digit(X),
  X1 is X+1 ,
  append( NumberAccumulator , [X1] , NumberAccumulator1 ) ,
  worker( Xs , NumberAccumulator1 , Numbers , LetterAccumulator , Letters ).
worker( [X|Xs] , NumberAccumulator , Numbers , LetterAccumulator , Letters ) :-
  letter(X) ,
  worker( Xs , NumberAccumulator , Numbers , [X|LetterAccumulator] , Letters ).
worker( [X|Xs] , NumberAccumulator , Numbers , LetterAccumulator , Letters ) :-
  not letter(X) ,
  not digit(X)  ,
  worker( Xs , NumberAccumulator , Numbers , LetterAccumulator , Letters ).

letter( a ). letter( b ). letter( c ). ... letter( z ).
letter('A'). letter('B'). letter('C'). ... letter('Z').

digit('0'). digit('1'). digit('2'). ... digit('9').

由于这是一个学习练习,我不会推迟列表的反转:尽管性能受到影响,我仍然会按照相反的顺序进行显而易见的构建列表。我相信这个练习的重点是你需要学习两种方式建立列表。