Prolog中的元组匹配
为什么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.
(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)不是原子的。