Prolog:显示每个子列表的每个元素

时间:2014-04-13 06:30:10

标签: prolog

我有一大堆较小的子列表,如:

 [ [005,Chester,100],[001,Bob,99],[002,Andy,77] ]

我正在尝试制作一个循环显示整个列表的显示“功能”,并显示如下:

 No.1: ID="005", Name="Chester", Grade=100
 No.2: ID="001", Name="Bob", Grade=99
 No.3: ID="002", Name="Andy", Grade=77
在prolog中思考很难,但我正在努力进行递归思考。非常感谢任何帮助!

4 个答案:

答案 0 :(得分:5)

只是通过递归来处理数据结构 - 我认为 - 这是Prolog的主要问题。

我们知道的数据结构缺乏表达能力是合适的形式,刺激了两个扩展(如B-Prolog中的循环)和语言 - 如Picat

无论如何,简单的Prolog它足以解决你的问题:

show_records(L) :-
    forall(nth1(N, L, E), format('No.~d:ID="~s",Name="~s",Grade="~d"~n', [N|E])).

产量

?- show_records([ ['005','Chester',100],['001','Bob',99],['002','Andy',77] ]).
No.1:ID="005",Name="Chester",Grade="100"
No.2:ID="001",Name="Bob",Grade="99"
No.3:ID="002",Name="Andy",Grade="77"
true.

答案 1 :(得分:1)

我的回答是用SWI-Prolog编写的,我提到的任何内置谓词的详细信息都可以通过searching the documentation获得。但是,我认为我在这里所说的一切都适用于其他突出的Prolog实现。如果我错了,请纠正我。

在Prolog中,我们使用谓词而不是函数,(或者,我们只使用返回真值的函数)。我将使用以下谓词在我的Prolog查询中引用您的示例列表:

ex([ [005,"Chester",100],[001,"Bob",99],[002,"Andy",77] ]).

为了将格式化文本写入标准输出流,我们将使用谓词format/2。它的签名是format(+Format, :Arguments),其中Format是包含特殊序列的原子,以便于插值。转义序列以波形符~开头,完整菜单可在SWI-Prolo documentation on format/2中找到。 Arguments是用于替换Format中的序列的prolog术语列表。在这个例子中,我们只需要~w,它写一个参数和~n,它写一个换行符。作为一般例子:例如,

?- format('Write ~w, then ~w, followed by ~w~n~n', ['this', 'that', 'the other']).
Write this, then that, followed by the other

true.

您将某个人表示为[ID, Name, Grade]表单的列表,因此我们只需要编写一个谓词,让我们在{34}中添加N。 N",然后我们可以将人员列表用于format/2的其余参数:

display_person(N, Person) :-
    format('No.~w: ID="~w", Name="~w", Grade=~w~n', [N|Person]).

format/2的第二个参数中,N以参数列表的头部为前缀。我们可以像这样测试谓词:

?- ex([P|Ps]), display_person(1, P).
No.1: ID="5", Name="Chester", Grade=100
P = [5, "Chester", 100],
Ps = [[1, "Bob", 99], [2, "Andy", 77]].

负责显示每个人列表。现在我们只需要遍历您的人员列表并显示每个成员。我们需要一个两位谓词,以便跟踪“{N}”的N值的增加值。显示的一部分,但我们只需要一个单位谓词就可以将列表传递给显示谓词。此要求使我们使用使用辅助谓词支持的前端谓词的通用模式:

display_people(People): -     display_people(1,People)。 %%使用起始值1

初始化对display_people/2的调用

display_people(_,[])。 display_people(N,[Person | People]): -     display_person(N,Person),     M是N + 1,     display_people(男,人)。

使用ex/1中的列表运行测试:

?- ex(Ps), display_people(Ps).
No.1: ID="5", Name="Chester", Grade=100
No.2: ID="1", Name="Bob", Grade=99
No.3: ID="2", Name="Andy", Grade=77
Ps = [[5, "Chester", 100], [1, "Bob", 99], [2, "Andy", 77]] ;
false.

然而,模式p([X|Xs]) :- q(X), p(Xs)正是maplist/n谓词的用途,因此我们可以节省一些打字,并且通过编写以下内容可以说明程序的声明含义更清晰:

display_people(People) :-
    length(People, NumPeople),
    numlist(1, NumPeople, Nums),
    maplist(display_person, Nums, People).

numlist(Low, High, Nums)会返回一个列表Nums,其值为LowHigh。在前面的定义中,maplist(display_person, Nums, People)基本上会为display_person(N, P)中的每NNums中的P People调用{{1}}。

答案 2 :(得分:1)

这个答案只是回答一位病理学家关于使用foldl的问题。我正在逐字复制他的display_person/2谓语:

display_person(N, Person) :-
    format('No.~w: ID="~w", Name="~w", Grade=~w~n', [N|Person]).

然后是一个小适配器,它将增加前一个谓词中的N(并以正确的顺序放置参数):

display_person(Person,N,NextN) :-
    display_person(N,Person),
    NextN is N+1.

并使用foldl

display_people(People) :-
    foldl(display_person,People,1,_).

如果

`People=[P1,P2,...,Pn]`

然后foldl(display_person,People,1,Rn)相当于:

display_person(People,1,R1),
display_person(People,R1,R2),
...
display_person(People,R(n-1),Rn).

以这种方式使用foldl可以避免通过列表一次获得它的长度。但是,另一方面,您需要一个适配器谓词。

无论如何,在这种情况下更好或更坏并不重要! foldl只是另一个有用的技巧,有时可以让你的代码更清晰。

答案 3 :(得分:0)

您不需要递归。首先,编写一个谓词,使用Prolog的format predicate显示每个条目,这是一个printf等价的,并直接将列表作为参数传递。其次,使用maplist将第一个谓词映射到列表上。

相关问题