【问题标题】:Implementing nth1 list operation in SWI prolog在 SWI prolog 中实现 nth1 列表操作
【发布时间】:2012-03-21 01:00:03
【问题描述】:

您将如何在 Prolog 中编写自己的谓词,以完全实现 nth1 函数的功能?

对于那些不熟悉该功能的人,最好通过一个例子来展示它的强大:

?- nth1(2, [a,b,c], E, R).

E = b

R = [a, c]

当调用 nth1 函数时,并传递以下内容: - 要从列表中删除的元素的索引(请注意,它不是零索引,在这里,我们传递的是索引 2) - 列表(在这种情况下,它是 [a,b,c]) - E,将分配从列表中删除的元素 - R,一个新列表,它将保存新列表,减去已删除的那个元素。

我不知道如何开始。任何意见,将不胜感激。我知道在 SWI-Prolog 中使用大约 3 或 4 行递归应该是可行的,我只是不知道从哪里开始。

【问题讨论】:

  • 标记为作业,考虑到问题的性质和原始发帖人的句柄 (Carleton U)

标签: list prolog predicate


【解决方案1】:

Check out this link 基本上应该会给你答案。为了让您开始,请考虑您的基本情况,它应该是

 nth1(1, [E|R], E, R).

现在你如何通过递归这个想法来编写其他案例?实际上,这只是掌握 Prolog 列表语法的窍门。

【讨论】:

    【解决方案2】:

    @EMS 的答案相当不错,但正确实施该谓词可能会很棘手。我们必须考虑每个对关系 nth1/4 有意义的实例化模式,因为这个问题需要完全相同的内置行为。所以 nth1 也可以搜索元素并在位置插入

    SWI-Prolog 用于在不同实现之间进行效率切换,但应该可以在需要时对关系测试实例化进行建模。

    我将其命名为 mth1 而不是 nth1。

    mth1(1, [X|R], X, R).
    mth1(_, L, _, _) :-
        L == [],  % (==)/2 fails when L is a var
        !, fail.
    mth1(P, [H|T], X, [H|R]) :-
        (  var(P)  % are we searching the position?
        -> mth1(Q, T, X, R),
           P is Q + 1
        ;  Q is P - 1,
           mth1(Q, T, X, R)
        ).
    

    插入需要测试L == []

    当然调试是必须的,这里做个简单的测试:

    ?- mth1(2,[a,b,c,d,e],X,Y).
    X = b,
    Y = [a, c, d, e] ;
    false.
    
    ?- mth1(X,[a,b,c,d,e],b,Y).
    X = 2,
    Y = [a, c, d, e] ;
    false.
    
    ?- mth1(2,X,b,[a,c,d,e]).
    X = [a, b, c, d, e] ;
    false.
    

    您应该检查是否涵盖了 SWI-Prolog 允许的所有实例化模式...

    如何执行这个简单的实现?这里是一个基本测试

    test_performance(N) :-
        numlist(1, N, L),
        time(test_performance(L, N, nth1)),
        time(test_performance(L, N, mth1)).
    
    test_performance(L, N, P) :-
        writeln(P),
        writeln('access last'),
        time((call(P, N, L, X, _), assertion(X == N))),
        writeln('find position of last'),
        time((call(P, Z, L, N, _), assertion(Z == N))),
        writeln('add tail'),
        time(call(P, N, _, tail, L)).
    

    令我惊讶的是,偷看元素并在尾部添加(略)快,而查找位置则慢得多(因为缺少尾部递归?):

    ?- test_performance(1000000).
    nth1
    access last
    % 1,000,011 inferences, 0,624 CPU in 0,626 seconds (100% CPU, 1602617 Lips)
    find position of last
    % 1,000,003 inferences, 0,670 CPU in 0,671 seconds (100% CPU, 1493572 Lips)
    add tail
    % 1,000,009 inferences, 0,482 CPU in 0,484 seconds (100% CPU, 2073495 Lips)
    % 3,000,243 inferences, 1,777 CPU in 1,781 seconds (100% CPU, 1688815 Lips)
    mth1
    access last
    % 1,000,002 inferences, 0,562 CPU in 0,563 seconds (100% CPU, 1779702 Lips)
    find position of last
    % 2,000,001 inferences, 1,998 CPU in 2,003 seconds (100% CPU, 1001119 Lips)
    add tail
    % 1,000,000 inferences, 0,459 CPU in 0,460 seconds (100% CPU, 2179175 Lips)
    % 4,000,223 inferences, 3,019 CPU in 3,027 seconds (100% CPU, 1324901 Lips)
    true .
    

    确实,位置搜索越长,就显示其效率低下,使用经典的 StackOverflow:

    ?- test_performance(2000000).
    nth1
    access last
    % 2,000,011 inferences, 1,218 CPU in 1,221 seconds (100% CPU, 1641399 Lips)
    find position of last
    % 2,000,003 inferences, 1,327 CPU in 1,330 seconds (100% CPU, 1507572 Lips)
    add tail
    % 2,000,009 inferences, 0,958 CPU in 0,960 seconds (100% CPU, 2088038 Lips)
    % 6,000,243 inferences, 3,504 CPU in 3,511 seconds (100% CPU, 1712549 Lips)
    mth1
    access last
    % 2,000,002 inferences, 1,116 CPU in 1,118 seconds (100% CPU, 1792625 Lips)
    find position of last
    % 1,973,658 inferences, 2,479 CPU in 2,485 seconds (100% CPU, 796219 Lips)
    % 3,973,811 inferences, 3,595 CPU in 3,603 seconds (100% CPU, 1105378 Lips)
    ERROR: Out of local stack
    

    【讨论】:

      【解决方案3】:

      建议在swi-prolog实现源码中搜索nth1:

      http://www.swi-prolog.org/pldoc/doc/swi/library/lists.pl?show=src

      棘手的是您必须生成或返回第 nth1 项,具体取决于您传入的未绑定变量。因此可能无法在几行内完成。

      【讨论】:

        【解决方案4】:

        首先,将问题分解为更小的组成部分。从列表中选择第 N 个项目很容易。收藏差别就小了。

        因此,将其分为两部分:

        • 首先,将列表拆分为前缀、所需项目和后缀。

        • 接下来,通过append/3将前缀和后缀连接起来形成余数列表。

        因此,您的 my_nth1\4 谓词应如下所示:

        nth1( N , List , Nth, Rest ) :-
          burst( N , List , Pfx , Nth , Sfx ) ,
          append( Pfx , Sfx , Rest )
          .
        
        % ------------------------------------------------------------------------------
        % burst a list into 3 parts - a prefix, an item and a suffix
        % based on the specified offset N (where 0 indicates the first item of the list)
        %
        % The prefix is built up using a "difference list" as we recurse down looking
        % for the Nth item.
        % ------------------------------------------------------------------------------
        burst( 0 , [L|Ls] , []      , L   , Ls  ).
        burst( N , [L|Ls] , [L|Pfx] , Nth , Sfx ) :- 
          N > 0 ,
          N1 is N - 1 ,
          burst( N1 , Ls , Pfx , Nth , Sfx )
          .
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-10-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多