【问题标题】:Prolog lists and recursionProlog 列表和递归
【发布时间】:2011-04-23 03:15:27
【问题描述】:

我在理解 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).

如何编写这段代码?

【问题讨论】:

    标签: list recursion prolog


    【解决方案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)
        ).
    

    【讨论】:

      【解决方案2】:

      foo([], 数字, 数字, 字母, 字母).

      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) :- 追加(字母_1,[X],字母_2)。

      【讨论】:

        【解决方案3】:

        我会这样做:

        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').
        

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-09-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多