Prolog 中的匹配元组

发布于 2024-09-02 10:33:40 字数 614 浏览 5 评论 0原文

为什么 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 中的列表吗?

Why does Prolog match (X, Xs) with a tuple containing more elements? An example:

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

Actually this is what I want to achieve but it seems suspicious. Is there any other way to treat a conjunction of terms as a list in Prolog?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夜唯美灬不弃 2024-09-09 10:33:40

使用 ,/2 运算符构建元组 term 在 PROLOG 中通常是右关联的(通常称为序列),因此您的输入a, b(c), d(e(f)), g 实际上很可能是术语 (a, (b(c), (d(e(f))), g)))。您的谓词 test2/1 打印了问题中显示的内容,这一事实证明了这一点,在第一次调用 test2/1 的第一个子句时,X 匹配 aXs 匹配 (b(c), (d(e(f)), g)) ,然后在第二次调用时 X 匹配 b(c)Xs 匹配 (d(e(f)), g),等等。

如果您确实想处理解释为连词的术语列表,您可以使用以下内容:

test2([X|Xs]) :- write(X), nl, test2(Xs).                                    
test2([]).

...on input [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 的意思 - 合取。

请参阅 op/3< 的手册页/a> 在 SWI-PROLOG 中了解更多细节 - 如果您不使用 SWI,我认为您使用的任何 PROLOG 实现中都应该有一个类似的谓词 - 如果它值得的话:-)

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

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]).

Tuple term construction with the ,/2 operator is generally right-associative in PROLOG (typically referred to as a sequence), so your input of a, b(c), d(e(f)), g might well actually be the term (a, (b(c), (d(e(f)), g))). This is evidenced by the fact that your predicate test2/1 printed what is shown in your question, where on the first invocation of the first clause of test2/1, X matched a and Xs matched (b(c), (d(e(f)), g)), then on the second invocation X matched b(c) and Xs matched (d(e(f)), g), and so on.

If you really wanted to deal with a list of terms interpreted as a conjunction, you could have used the following:

test2([X|Xs]) :- write(X), nl, test2(Xs).                                    
test2([]).

...on input [a, b(c), d(e(f)), g]. The list structure here is generally interpreted a little differently from tuples constructed with ,/2 (as, at least in SWI-PROLOG, such structures are syntactic sugar for dealing with terms constructed with ./2 in much the same way as you'd construct sequences or tuple terms with ,/2). This way, you get the benefits of the support of list terms, if you can allow list terms to be interpreted as conjunctions in your code. Another alternative is to declare and use your own (perhaps infix operator) for conjunction, such as &/2, which you could declare as:

:- op(500, yfx, &). % conjunction constructor

You could then construct your conjunct as a & b(c) & d(e(f)) & g and deal with it appropriately from there, knowing exactly what you mean by &/2 - conjunction.

See the manual page for op/3 in SWI-PROLOG for more details - if you're not using SWI, I presume there should be a similar predicate in whatever PROLOG implementation your'e using -- if it's worth it's salt :-)

EDIT: To convert a tuple term constructed using ,/2 to a list, you could use something like the following:

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]).
各自安好 2024-09-09 10:33:40

嗯... 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.

Hmm... a, b(c), d(e(f)), g means a and (b(c) and (d(e(f)) and g)), as well list [1,2,3] is just a [1 | [2 | [3 | []]]]. I.e. if you turn that conjuction to a list you'll get the same test2([X|Xs]):-..., but difference is that conjunction carries information about how that two goals is combined (there may be disjunction (X; Xs) as well). And you can construct other hierarchy of conjunctions by (a, b(c)), (d(e(f)), g)

You work with simple recursive types. In other languages lists is also recursive types but they often is pretending to be arrays (big-big tuples with nice indexing).

Probably you should use:

test2((X, Y)):- test2(X), nl, test2(Y).
test2((X; Y)). % TODO: handle disjunction
test2(X) :- write(X), nl.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文