Prolog-每次递归运行都追加到新列表吗?

时间:2020-04-30 02:24:21

标签: prolog

Hiyya,

我目前正在Prolog中从事某种“虚拟商店”的工作,并且我正在尝试开发更新过道的功能。但是,由于我对Prolog的了解有限,因此我遇到了一些困难。

谓词和调用:

/*  % First parameter: The shop (or "old list") that contains the unmodified data
    % Second parameter: Simply a index/counter keeping track of where we are in 
        the "recursive loop"
    % Third parameter: Index of where we want to get. We keep recursively looping 
        and either incrementing or decrementing until the second and third 
        parameters are the same.
    % Fourth parameter: Since the first parameter is a list of lists, this 
        parameter will contain the "inner list" which will replace another inner 
        list.
    % Fifth parameter: The shop (or "new list"), the result, whatever you'd like 
        to call it 
    */
update_aisle( [H|T], CurrentAisle, TargetAisle, NewObj, NewShop):-
    CurrentAisle < TargetAisle,
    Temp is CurrentAisle + 1,
    append( NewShop, H),
    update_aisle( T, Temp, TargetAisle, NewObj, NewShop).
update_aisle( [H|T], CurrentAisle, TargetAisle, NewObj, NewShop):-
    CurrentAisle > TargetAisle,
    Temp is CurrentAisle - 1,
    append( NewShop, H),
    update_aisle( T, Temp, TargetAisle, NewObj, NewShop).
update_aisle( [H|T], CurrentAisle, TargetAisle, NewObj, NewShop):-
    CurrentAisle is TargetAisle,
    nth0( 0, T, TempT),
    append( NewObj, TempT, NewShop).

?- Shop = [ [ "Bread", "Donuts", "Cookies" ], 
            [ "Beer", "Cider", "Juice" ],
            [ "Ham", "Raw Meat", "Sausage" ] ],
   write(Shop), nl,
   update_aisle(Shop, 0, 1, ["Beer", "Milk", "Juice"], NewShop),
   write(NewShop), nl.

现在,我只会得到指令(失败),所以根本不会走得太远(而且我会假设这是因为append/2并未按照我的意愿进行合作)。但是,我想要实现的是:

Shop = [ [ "Bread", "Donuts", "Cookies" ], 
         [ "Beer", "Cider", "Juice" ],
         [ "Ham", "Raw Meat", "Sausage" ] ].

NewShop = [ [ "Bread", "Donuts", "Cookies" ], 
            [ "Beer", "Milk", "Juice" ], 
            [ "Ham", "Raw Meat", "Sausage" ] ].

因此,换句话说,我试图遍历列表,并为每个递归循环附加列表的“头”,只要我们不在列表中即可。一旦达到这一点,我们通常会在将NewObj附加到列表(而不是头部,因为它是被替换的头部)之后并完成工作。

我觉得我缺少明显的东西,但任何帮助都将不胜感激!

1 个答案:

答案 0 :(得分:1)

如果我正确地解释了您的问题,那么您想要替换列表中给定索引处的项目:

% replace_at( In, At, With, Replaced )
replace_at( [],  _I, _N, []).
replace_at( [_|T], I, N, [N|T]) :- I =:= 0.
replace_at( [H|T], I, N, [H|T2]) :- I > 0, I2 is I-1,
   replace_at( T, I2, N,    T2).

测试:

?- Shop = [["Bread","Donuts","Cookies"],["Beer","Cider","Juice"],["Ham","Raw Meat","Sausage"]], 
   replace_at( Shop, 1,    ["Beer", "Milk", "Juice"],    NewShop), nl, 
   maplist( writeln, Shop), nl, maplist( writeln, NewShop), nl.

[Bread,Donuts,Cookies] 
[Beer,Cider,Juice]
[Ham,Raw Meat,Sausage]

[Bread,Donuts,Cookies]
[Beer,Milk,Juice]
[Ham,Raw Meat,Sausage]

Shop = [["Bread", "Donuts", "Cookies"], ["Beer", "Cider", "Juice"], ["Ham", "Raw Meat", "Sausage"]],
NewShop = [["Bread", "Donuts", "Cookies"], ["Beer", "Milk", "Juice"], ["Ham", "Raw Meat", "Sausage"]] ;
false.

提供所需的输出。

列表中的元素本身就是列表,在这里并不重要。

如果另一方面,您将要在调用中使用两个索引,请指定第J个列表中的第I个元素(0 -基于)在要替换的列表列表中,您只需使用上述谓词两次即可完成:

% replace_at2d( In, AtLine, AtWord, With, Replaced )
replace_at2d(  LL,    I, J, W,     LL2 ) :-
  nth0(   I,   LL, L),                         % I-th line
  replace_at(      L,    J, W, L2 ),           % J-th word
  replace_at(  LL,    I,       L2, LL2 ).

测试:

?- Shop = [["Bread","Donuts","Cookies"],["Beer","Cider","Juice"],["Ham","Raw Meat","Sausage"]], 
   replace_at2d( Shop, 1, 1,    "Milk",    NewShop), nl, 
   maplist( writeln, Shop), nl, maplist( writeln, NewShop), nl.

[Bread,Donuts,Cookies]
[Beer,Cider,Juice]
[Ham,Raw Meat,Sausage]

[Bread,Donuts,Cookies]
[Beer,Milk,Juice]
[Ham,Raw Meat,Sausage]

Shop = [["Bread", "Donuts", "Cookies"], ["Beer", "Cider", "Juice"], ["Ham", "Raw Meat", "Sausage"]],
NewShop = [["Bread", "Donuts", "Cookies"], ["Beer", "Milk", "Juice"], ["Ham", "Raw Meat", "Sausage"]] ;
false.