我有一大堆较小的子列表,如:
[ [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中思考很难,但我正在努力进行递归思考。非常感谢任何帮助!
答案 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
,其值为Low
到High
。在前面的定义中,maplist(display_person, Nums, People)
基本上会为display_person(N, P)
中的每N
和Nums
中的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将第一个谓词映射到列表上。