如何在Prolog中获取tuple的第一个或第二个元素?
在Prolog中获取元组(项对)的第一个/第二个元素
嘿,我来帮你搞定这个问题!你提到用arg没成功,其实是因为没搞清楚Prolog里“元组”的本质——你列表里的(pos(1,2), pos(1,3))这类结构,是Prolog内置的项对(pair),本质是','/2这个复合函子的实例,所以arg其实是能用的,不过还有更直观的模式匹配方法,下面给你详细拆解:
方法一:直接模式匹配(最直观)
Prolog的强项就是模式匹配,对于列表里的每个元组,直接用(A, B)的结构就能解构出第一个元素A和第二个元素B。我们可以写两个简单的谓词来批量提取列表中所有元组的首尾元素:
% 提取列表中所有元组的第一个元素 get_first_elements([], []). get_first_elements([(First, _)|RestPairs], [First|RestFirsts]) :- get_first_elements(RestPairs, RestFirsts). % 提取列表中所有元组的第二个元素 get_second_elements([], []). get_second_elements([(_, Second)|RestPairs], [Second|RestSeconds]) :- get_second_elements(RestPairs, RestSeconds).
用你给出的Pairs列表测试的例子:
?- Pairs = [(pos(1,2), pos(1,3)), (pos(1,2), pos(2,1))], get_first_elements(Pairs, Firsts). Firsts = [pos(1,2), pos(1,2)].
方法二:用arg函数(你原来的思路)
你之前以为arg只对“谓词”生效,其实Prolog里所有结构化的项都是复合项,包括这个逗号分隔的元组——(A,B)等价于','(A,B),所以我们可以直接用arg/3来取它的第1或第2个参数:
% 取单个元组的第一个元素 ?- arg(1, (pos(1,2), pos(1,3)), First). First = pos(1,2). % 取单个元组的第二个元素 ?- arg(2, (pos(1,2), pos(1,3)), Second). Second = pos(1,3).
如果要批量处理列表,可以结合maplist简化代码:
get_first_elements(Pairs, Firsts) :- maplist(extract_first, Pairs, Firsts), extract_first(Pair, First) :- arg(1, Pair, First). get_second_elements(Pairs, Seconds) :- maplist(extract_second, Pairs, Seconds), extract_second(Pair, Second) :- arg(2, Pair, Second).
方法三:用lambda简化(SWI-Prolog等支持的话)
如果你的Prolog环境支持lambda表达式(比如SWI-Prolog的library(lambda)),还能写得更简洁:
:- use_module(library(lambda)). get_first_elements(Pairs, Firsts) :- maplist(\(A,_)^A, Pairs, Firsts). get_second_elements(Pairs, Seconds) :- maplist(\(_,B)^B, Pairs, Seconds).
总结一下,模式匹配是最易读的方式,而arg也完全能用,只是需要意识到逗号项本质是','/2复合项~
内容的提问来源于stack exchange,提问作者Vlad Nicola
相关产品推荐
相关产品推荐

