首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Prolog:显示每个子列表的每个元素

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

Stack Overflow用户
提问于 2014-04-13 06:30:10
回答 4查看 247关注 0票数 3

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

代码语言:javascript
复制
 [ [005,Chester,100],[001,Bob,99],[002,Andy,77] ]

我正在尝试创建一个显示“函数”,它循环遍历整个列表并显示如下:

代码语言:javascript
复制
 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中的思考已经够困难了,但我正在与递归思维作斗争。任何帮助都是非常感谢的!

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-04-13 09:25:34

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

数据结构缺乏表现力(我们知道数据结构的形状是适当的),这刺激了扩展(如both中的循环)和语言(如皮卡特 )。

总之,简单的Prolog --它的强大功能足以解决您的问题:

代码语言:javascript
复制
show_records(L) :-
    forall(nth1(N, L, E), format('No.~d:ID="~s",Name="~s",Grade="~d"~n', [N|E])).

收益率

代码语言:javascript
复制
?- 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.
票数 5
EN

Stack Overflow用户

发布于 2014-04-13 08:58:58

我的答案是用SWI编写的,我提到的任何内置谓词的详细信息都可以由搜索文档获得。但是,我认为我在这里所说的一切都适用于其他著名的Prolog实现。如果我错了,请纠正我。

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

代码语言:javascript
复制
ex([ [005,"Chester",100],[001,"Bob",99],[002,"Andy",77] ]).

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

代码语言:javascript
复制
?- 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的列表],因此我们只需要编写一个谓词,该谓词将允许我们在“so”中添加N,然后我们可以将person-list用于format/2的其余参数。

代码语言:javascript
复制
display_person(N, Person) :-
    format('No.~w: ID="~w", Name="~w", Grade=~w~n', [N|Person]).

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

代码语言:javascript
复制
?- 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]].

负责显示每个人的名单。现在,我们只需要遍历您的人员列表并显示每个成员。为了跟踪显示的‘to’部分的N值的增加,我们需要一个双位置谓词,但是我们只需要一个位置谓词就可以将列表传递给显示谓词。这一需求导致我们使用了使用由辅助谓词支持的前端谓词的通用模式:

Display_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(M,People)。

使用来自ex/1的列表运行测试

代码语言:javascript
复制
?- 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谓词的目的,因此我们可以节省一些输入,并且可以通过编写以下代码使程序的声明意义更加清晰:

代码语言:javascript
复制
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)实际上将对Nums中的每一对NPeople中的P调用display_person(N, P)

票数 1
EN

Stack Overflow用户

发布于 2014-04-13 09:20:10

这个答案仅仅是为了回答aBathologist关于foldl的使用。我逐字复制他的display_person/2谓词:

代码语言:javascript
复制
display_person(N, Person) :-
    format('No.~w: ID="~w", Name="~w", Grade=~w~n', [N|Person]).

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

代码语言:javascript
复制
display_person(Person,N,NextN) :-
    display_person(N,Person),
    NextN is N+1.

并使用foldl

代码语言:javascript
复制
display_people(People) :-
    foldl(display_person,People,1,_).

如果

代码语言:javascript
复制
`People=[P1,P2,...,Pn]`

那么foldl(display_person,People,1,Rn)就相当于:

代码语言:javascript
复制
display_person(People,1,R1),
display_person(People,R1,R2),
...
display_person(People,R(n-1),Rn).

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

无论如何,无论是好是坏,在这种情况下都不重要!foldl只是另一个很好知道的技巧,有时还可以使代码更简洁。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23039916

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档