Prolog如何使用参数对类型进行模式匹配

Prolog如何使用参数对类型进行模式匹配,prolog,Prolog,我正在努力学习Prolog,我是一个初学者。为了理解它,我尝试编写一个函数。我有一个以这种方式定义的类型: a(X,Y,Z). 比如说,我的知识库是: a(M,2,3) . a(S,4,7) . 这里X是操作,Y,Z是将要进行此操作的数字。我有一个函数f,它将执行这个运算,如果这个运算得到的结果是f的第二个参数,它将返回true。否则,它将返回操作的结果 比如说, g(M,4) 应该屈服于 6. 因为M代表乘法,6不等于4。那么让我们假设s代表和运算 g(S,11) 由于4+7=1

我正在努力学习Prolog,我是一个初学者。为了理解它,我尝试编写一个函数。我有一个以这种方式定义的类型:

a(X,Y,Z). 
比如说,我的知识库是:

a(M,2,3) .
a(S,4,7) .
这里X是操作,Y,Z是将要进行此操作的数字。我有一个函数f,它将执行这个运算,如果这个运算得到的结果是f的第二个参数,它将返回true。否则,它将返回操作的结果

比如说,

g(M,4) 
应该屈服于

6.
因为M代表乘法,6不等于4。那么让我们假设s代表和运算

g(S,11)
由于4+7=11,应导致true

所以,我尝试的是:

g([],0) .
g(a(M,X,Y),Z, true :- (Z =:= (X*Y) ) ) .
g(a(S,X,Y),Z, true :- (Z =:= (X+Y) ) ) .
g(a(M,X,Y),Z, (X*Y) ) .
g(a(S,X,Y),Z, (X+Y) ) .
但是当我打电话的时候 g(S,11)

我明白了

false.
虽然它应该评估为11

当我打电话时

g(S,45)
我应该得到11分,但我仍然得到

false.

我是非常非常的初学者,所以如果我遗漏了一些明显的东西,请不要太苛刻,提前谢谢。

不幸的是,在你接近你试图在这里做的事情之前,你确实需要学习更多关于Prolog的知识。首先,Prolog没有函数,只有谓词。这不仅仅是一个有趣的名字,它是一个根本不同的概念

Prolog谓词的求值方式与您期望的不同。它们要么失败,要么成功,在成功的情况下,它们可以将一些变量绑定到值。在其他语言中,这看起来像是“返回”一个值,但事实并非如此

让我们看看您的程序的这个版本:

a(mul, 2, 3).
a(add, 4, 7).

g(mul, Z) :-
    a(mul, X, Y),
    Z is X * Y.
g(add, Z) :-
    a(add, X, Y),
    Z is X + Y.
我可以询问11是否是数据库中存储的操作数相加的正确结果:

?- g(add, 11).
true.
我也可以问它正确的结果是什么,而不提供我的猜测:

?- g(add, Result).
Result = 11.
但你不能让它在错误的猜测中“返回”正确的解决方案:

?- g(add, 45).
false.
这是因为任何“返回”值都会通过绑定查询中的变量来实现。但是这个查询不包含任何变量!您永远无法从这样的查询中“获取”值


无论您的目标是什么,都可以在Prolog中完成,但您目前没有走上正确的轨道。您应该首先尝试更多地理解逻辑变量等概念,以及使用
a(mul,X,Y)等术语的区别
在程序中作为子句出现,而不是作为谓词的参数出现。

不幸的是,您需要了解有关Prolog的更多信息,然后才能接近您在这里尝试的操作。首先,Prolog没有函数,只有谓词。这不仅仅是一个有趣的名字,它是一个根本不同的概念

Prolog谓词的求值方式与您期望的不同。它们要么失败,要么成功,在成功的情况下,它们可以将一些变量绑定到值。在其他语言中,这看起来像是“返回”一个值,但事实并非如此

让我们看看您的程序的这个版本:

a(mul, 2, 3).
a(add, 4, 7).

g(mul, Z) :-
    a(mul, X, Y),
    Z is X * Y.
g(add, Z) :-
    a(add, X, Y),
    Z is X + Y.
我可以询问11是否是数据库中存储的操作数相加的正确结果:

?- g(add, 11).
true.
我也可以问它正确的结果是什么,而不提供我的猜测:

?- g(add, Result).
Result = 11.
但你不能让它在错误的猜测中“返回”正确的解决方案:

?- g(add, 45).
false.
这是因为任何“返回”值都会通过绑定查询中的变量来实现。但是这个查询不包含任何变量!您永远无法从这样的查询中“获取”值


无论您的目标是什么,都可以在Prolog中完成,但您目前没有走上正确的轨道。您应该首先尝试更多地理解逻辑变量之类的概念,以及类似
a(mul,X,Y)
这样的术语在程序中作为子句出现与相同术语作为谓词的参数出现的区别。

您发布的代码有很多问题。特别是,它不是定义Prolog谓词的正确语法,它使用变量(以大写字母开头),而不是我认为的原子

例如,您的代码:

g(a(M,X,Y),Z, true :- (Z =:= (X*Y) ) ) . 
简单地断言一个看起来像这样的术语,写得“规范”:

它是一个有效的Prolog术语,但不是用于断言谓词的Prolog语法。对于谓词,顶级函子必须是
:-
(通常为
头:-body
,或按规范编写的
:-(头,体)
)。在代码中,顶级函子是
g
,它对Prolog没有特殊意义

您可以使用操作符本身作为操作的描述,而不是定义其他原子来表示这些操作。因此,您的知识库可能如下所示:

a(*, 2, 3).
a(*, 4, 5).
a(+, 2, 4).
a(+, 4, 7).
g(+, 11).
查询可能如下所示:

a(*, 2, 3).
a(*, 4, 5).
a(+, 2, 4).
a(+, 4, 7).
g(+, 11).
那么谓词将是:

g(Operation, Result) :-
    a(Operation, Operand1, Operand2),
    Expression =.. [Operation, Operand1, Operand2] ,
    Result #= Expression.
a(mul, 2, 3).
a(mul, 4, 5).
a(add, 2, 4).
a(add, 4, 7).
这里,我们查询具有可接受操作数的操作。然后,我们使用
=../2
将操作数和操作数统一为一个Prolog术语,该术语由一个函子(列表的第一个元素)和参数(列表的其余部分)组成。然后,我们使用CLP(FD)
#=
操作对整数进行适当的推理,因为它提供了最通用的解决方案,并对
表达式
中的术语给出的表达式进行求值。根据上述事实,得出以下结果:

| ?- g(+, 11).

yes
| ?- g(+, R).

R = 6 ? ;

R = 11

(1 ms) yes
| ?- g(Op, 11).

Op = (+)

yes
| ?- g(Op, 6).

Op = (*) ? ;

Op = (+) ? ;

no

如果确实需要运算符使用不同的符号表示,可以定义别名映射:

alias(add, +).
alias(mul, *).
你的事实是:

g(Operation, Result) :-
    a(Operation, Operand1, Operand2),
    Expression =.. [Operation, Operand1, Operand2] ,
    Result #= Expression.
a(mul, 2, 3).
a(mul, 4, 5).
a(add, 2, 4).
a(add, 4, 7).
然后定义:

g(Operation, Result) :-
    a(Operation, Operand1, Operand2),
    alias(Operation, Op),
    Expression =.. [Op, Operand1, Operand2] ,
    Result #= Expression.

你发布的代码有很多问题。特别是,它不是定义Prolog谓词的正确语法,它使用变量(以大写字母开头),而不是我认为的原子

例如,您的代码:

g(a(M,X,Y),Z, true :- (Z =:= (X*Y) ) ) . 
简单地断言一个看起来像这样的术语,写得“规范”:

它是一个有效的Prolog术语,但不是用于断言谓词的Prolog语法。对于谓词,顶级函子必须是
:-
(通常为
头:-body
,或按规范编写的
:-(头,体)