Prolog中的元组匹配

Prolog中的元组匹配,prolog,tuples,pattern-matching,operators,associativity,Prolog,Tuples,Pattern Matching,Operators,Associativity,为什么Prolog将(X,Xs)与包含更多元素的元组相匹配?例如: test2((X, Xs)) :- write(X), nl, test2(Xs). test2((X)) :- write(X), nl.

为什么Prolog将
(X,Xs)
与包含更多元素的元组相匹配?例如:

test2((X, Xs)) :- write(X), nl, test2(Xs).                                    
test2((X)) :- write(X), nl.                                                   
                                                                              
test :-                                                                       
        read(W),                                                               
        test2(W). 

?- test.
|: a, b(c), d(e(f)), g.
a
b(c)
d(e(f))
g
yes
事实上,这就是我想要实现的目标,但这似乎是可疑的。在Prolog中,还有其他方法可以将术语的连词作为列表处理吗?

嗯<代码>a,b(c),d(e(f)),g意味着
a
和(
b(c)
和(
d(e(f))
g
),以及列表
[1,2,3]
只是一个
[1,2,3]
。也就是说,如果你把这个连词转换成一个列表,你会得到相同的
test2([X | Xs]):-…
,但不同的是,连词携带了关于这两个目标如何组合的信息(也可能存在分离
(X;Xs)
)。你可以通过
(a,b(c)),(d(e(f)),g)来构造其他的连词层次结构

您可以使用简单的递归类型。在其他语言中,列表也是递归类型,但它们常常假装是数组(具有良好索引的大元组)

可能您应该使用:

test2((X, Y)):- test2(X), nl, test2(Y).
test2((X; Y)). % TODO: handle disjunction
test2(X) :- write(X), nl.
带有
,/2
运算符的元组术语构造在PROLOG中通常是右关联的(通常称为序列),因此
a,b(c),d(e(f)),g
的输入实际上可能就是术语
(a,(b(c),(d(e(f)),g))
。你的谓词
test2/1
打印了你问题中显示的内容,在第一次调用
test2/1
的第一个子句时,
X
匹配
a
Xs
匹配
(b(c)、(d(e(f)),g))
,然后在第二次调用
X
匹配
b(c) 
Xs
匹配
(d(e(f)),g)
,依此类推

如果您真的想处理一系列被解释为连词的术语,您可以使用以下方法:

test2([X|Xs]) :- write(X), nl, test2(Xs).                                    
test2([]).
conjunct_to_list((A,B), L) :-
  !,
  conjunct_to_list(A, L0),
  conjunct_to_list(B, L1),
  append(L0, L1, L).
conjunct_to_list(A, [A]).
…在输入时
[a,b(c),d(e(f)),g]
。这里的列表结构通常与用
,/2
构造的元组有点不同(至少在SWI-PROLOG中,这种结构是处理用
/2
构造的术语的语法糖,其方式与用
,/2
构造序列或元组术语的方式大致相同。)。通过这种方式,如果您可以允许在代码中将列表项解释为连词,则可以获得列表项支持的好处。另一种方法是声明并使用您自己的连词(可能是中缀运算符),例如
&/2
,您可以声明为:

:- op(500, yfx, &). % conjunction constructor
然后,您可以将您的连词构造为
a&b(c)和d(e(f))&g
,并从那里适当地处理它,确切地知道您所说的
&/2
-连词是什么意思

有关更多详细信息,请参阅SWI-PROLOG中的手册页-如果您没有使用SWI,我认为您使用的任何PROLOG实现中都应该有一个类似的谓词-如果值得的话:-)

编辑:要将使用
,/2
构造的元组术语转换为列表,可以使用以下内容:

test2([X|Xs]) :- write(X), nl, test2(Xs).                                    
test2([]).
conjunct_to_list((A,B), L) :-
  !,
  conjunct_to_list(A, L0),
  conjunct_to_list(B, L1),
  append(L0, L1, L).
conjunct_to_list(A, [A]).

你的帖子回答了为什么这样的构造会起作用(,/2运算符),但我仍然不知道这是否是处理此类输入的正确方法。问题是,我不能只处理术语列表,因为我在输入时得到了元组。也许有一种方法可以将元组转换为列表?我仍然可以这样做:转换((X,Xs),[X | R]):convert(Xs,R).convert(X,[X])。我添加了
conconcent_to_list/2
,这应该有助于将用
,/2
构造的术语转换为list(
/2
)。你可以这样写第一个
concent_to_list((a,B),[a | T]:-!,concent u to_to_list((B),T)。但是没有一个方法可以做到没有<代码>!< /Cord>?@ OrcBi,你错了。考虑在代码< >(<,b)< />代码> <代码> a=(a,b)< /> >和<代码> b=(c,d)< /代码>。你的例子(如果一个基本情况被适当包含)可能会产生列表<代码> [(a,b),c,d]
。请注意,在我的定义中,有两个调用同时展开
A
B
,以处理此类嵌套术语。事实上,它会正确地将任何
,/2
嵌套术语折叠到列表中。@sharky我尝试了你的解决方案,如果你删除切割,它实际上与[(A,B,c)]匹配。我现在不确定[(A,B),c,d],但是[A,B,(c,d)]。也将匹配。您的解决方案与我的解决方案有完全相同的问题,问题出现在第二条中,因为A可以统一为(c,d)。同时,我通过添加原子(A)来解决它,因为(c,d)不是原子的。