我刚刚开始在大学学习Prolog,我有一个概念问题,我没有找到任何具体的答案:
我想要将这种语言的“哲学”内化,所以我想非常准确地理解复杂的术语是什么(或复合词)。到现在为止,我已经读到一个复杂的术语是一个仿函数而且它是正统的。我可以使用这样的复杂术语构建知识库:
love(john, sarah).
让我们说现在,我可以输入任何可能的字符串对作为“爱”的参数,除非字符串对是“john,sarah”,否则它将是假的。是的,所以对仿函数及其论证的“问题”是真的还是假的,这取决于我是否在我的知识库中特别说过,或者Prolog是否能够根据他使用规则,统一等信息来推断它
是的,从这里开始,我理解一个复杂的术语表示n个实体之间的关系是 true或false 。我不明白的是:
vertical(line(point(X,Y),point(X,Z))).
我明白什么点(X,Y)。确实。它说任何实体都通过“点”与任何其他实体相关。我不明白的是点(X,Y)如何成为线的参数!到目前为止,一个复杂的术语只是说实体是否相关。我可以理解它是一个“传统函数”,如果实体是相关的,则返回true或false。但这怎么可能是线的论点?理论上,“线”有2个参数(实体),它会说它们是否相关。现在,参数的值是真还是假?
我能理解“点(X,Y)”正在创建一个对象“点”。所以行的参数是一个“点实体”。但到目前为止,这并不是我读过的关于复杂术语的内容,所以我希望能够通过技术定义来解释嵌套案例。
(如果我使用了错误的术语或定义,我很抱歉,我是Prolog的新手)
谢谢!
答案 0 :(得分:2)
我理解一个复杂的术语表示n个实体之间的关系在理论上是真或假[line],有2个参数(实体),它会说它们是否相关。
遗憾的是,您对“复杂术语”的解释是错误的。 Prolog使用这些术语来表示“程序”和“数据”,因此术语的解释取决于它出现的上下文以及如何使用它。
考虑你的第一个例子:
love(john, sarah).
从最后的时期(以及您在知识库的上下文中提到这一点的事实),我们知道这必须作为Prolog文件中的顶级构造出现。这些术语定义了谓词的子句。这些是“程序”:这个术语定义谓词love/2
的一个子句(/2
是术语的常用Prolog表示法,即参数的数量)。我们可以通过“调用”它来将其用作“程序”:
?- love(X, Y).
X = john,
Y = sarah.
在这个“程序”上下文中,我们可以说love/2
是两个术语之间的关系。
但在第二个示例中,line
字词不出现在顶层。它嵌套在vertical/1
术语中:
vertical(line(point(X,Y),point(X,Z))).
这意味着定义的“程序”是vertical/1
,在术语上是一个单一的关系。 (将它称为“一组术语”更自然。在这个例子中,“垂直线的集合是两个点具有相同 X 坐标”的所有线的集合。) line/2
不被定义为关系;它只是未解释的数据。我们可以致电vertical/1
:
?- vertical(T).
T = line(point(_G921, _G922), point(_G921, _G925)).
但不是line/2
:
?- line(P1, P2).
ERROR: toplevel: Undefined procedure: line/2 (DWIM could not correct goal)
摘要:只有“顶级”字词定义谓词,只有这些字词才能被解释为关系。程序中出现的其他术语只是关系所涉及的“数据”。
答案 1 :(得分:2)
这是一个很好的问题,因为Prolog许多Prolog初学者来自命令式语言的背景,这是一个基本的混乱点。我在学习Prolog时的建议通常是,#34;忘记(几乎)你所学到的关于编程的一切,并从基础知识开始#34;。
Prolog建立在可以包含零个或多个参数的术语上。 foo
是一个没有参数的术语。 foo(A, B)
是一个带有两个参数的术语。 foo(bar(X), bah(Y,Z))
是一个带有两个参数的复杂术语(称为foo/2
),其参数由术语bar/1
(有一个参数)和bah/2
(有两个参数)组成
即使谓词子句是Head :- Body
形式的术语,也可以是规范形式的':-'(Head, Body)
。当这种术语在Prolog程序中声明(在文件中静态声明,甚至动态声明)时,Prolog将其识别为谓词,因为Prolog为某些术语赋予了特殊含义,{{{在这种情况下,1}}用于谓词子句定义。但如果没有这种背景,:-
仍然只是一个术语"。
在Prolog中,除了预定义的术语(例如':-'(A, B)
,运算符等)之外,程序员定义的术语的语义仅取决于程序员决定的内容和上下文(查询?断言?另一个术语?),用于他们的程序。
我明白什么点(X,Y)。确实。它说任何实体都通过" point"。
与任何其他实体相关
在Prolog中,:-
是一个带有两个参数(point(X, Y)
)的术语,除了程序员决定之外没有任何语义含义(没有'#34;做"任何事情)然后他们在程序中使用它。如果我在Prolog提示符下输入point/2
,如下:
point(X, Y)
Prolog将此视为查询,并尝试查找与?- point(1, 2).
匹配的事实或规则,并允许其成功。但是,如果我输入了:
point(1, 2)
Prolog只是看到?- foo(point(1, 2)).
上的查询查找与foo/1
匹配的事实或规则,foo(_)
是"只是一个术语"没有进一步的解释,除非有一个谓词子句将它放在一个上下文中。例如,如果point(1, 2)
我的数据库中只有一个事实foo/1
而且foo(a).
没有规则,foo/1
会失败,因为Prolog会尝试将术语foo(point(1, 2)).
(带有零参数的术语)与术语a
(带有2个参数的术语)匹配,并且会失败,并且没有其他选择可以尝试。如果我有point(1, 2Y)
的条款看起来像这样:
foo/1
然后,通过将foo(X) :-
X = point(A,B),
... % do some things involving A and B
与foo(point(1,2))
统一,查询X
将匹配此条款的标题,然后此子句的第一行将统一point(1,2)
并统一{{在此上下文中,1}}和point(1, 2) = point(A, B)
等A = 1
不会以任何方式调用或执行。
假设我有以下B = 2
条款:
point/2
现在,如果我查询foo/1
,foo(X) :-
call(X),
...
将尝试调用 foo(point(1, 2)).
(将其作为查询执行),Prolog将尝试查找事实或与foo/1
匹配的规则。
我不明白的是点(X,Y)如何成为线的参数!
请记住,这只是一个术语。除非在特定上下文中使用,否则它没有语义。直到你在Prolog中以某种方式运用这个术语,除了程序员的头脑之外没有任何意义。程序员可以决定定义术语point(1, 2)
,该术语表示从点point(1, 2)
到点line(A, B)
的行。如果我们有一个术语,我们想在两个坐标A
上定义一个点,我们也可以说B
。通过程序员约定,这意味着,我从(point(X, Y)
,line(point(X1, Y1), point(X2, Y2))
)指向一条线,指向(X1
,Y1
)
到目前为止,一个复杂的术语只是说实体是否相关。
我不确定你为什么说"直到现在"。用户决定该关系是什么,以及如何组织(复杂)术语来表示该关系。当我们说X2
时,Y2
可以(由程序员自行决定)代表从line(point(X1, Y1), point(X2, Y2))
到(X1, Y1)
的一行。
我能理解它是一种传统功能"如果实体是相关的,则返回true或false。
事实并非如此。该术语不形成传统功能" 返回 (X2, Y2)
或true
。这只是一个术语,不会返回任何东西。正如我所提到的,在Prolog中,术语的行为确实取决于上下文。术语可以是查询,这意味着它被称为,而Prolog将尝试(通过先前声明的事实和规则/谓词)确定它是可证明的或真实的。在这种情况下,它将事实或规则与顶级术语仿函数名称相匹配。因此,如果您实际上查询 false
,Prolog会查找与line(point(X1, Y1), point(X2, Y2))
匹配的事实或规则并从那里开始。然后它会成功或失败,具体取决于它是否能够匹配事实,或成功完成规则。
但这怎么可能是线的论点? "线"从理论上讲,它有2个参数(实体),它会说它们是否相关。
line(_, _)
是一个术语,根据程序员的惯例,代表从line(point(X,Y), point(X,Z))
点到(X, Y)
点的一行。
现在,论点'值是真还是假?
不,这些论点根本没有任何值。它们只是定义程序员选择代表的东西的术语或结构。
我能理解"点(X,Y)"正在创建一个对象"指向"。
它不会创建一个对象。它只是一个代表横坐标(X, Z)
和纵坐标X
的点的术语。
因此,line的参数是一个"点实体"。
Y
有两个参数,它们代表定义一条线的两个不同点(按照程序员的惯例)。如果它表示为line/2
,那么"形式"没有指定点(程序员可以选择用列表表示一个点,例如line(P1, P2)
,或者在这种情况下,用户定义的术语[X, Y]
)。
但到目前为止,这并不是我所读到的关于复杂术语的内容,所以我希望能够通过技术定义来解释嵌套案例。
到目前为止,您对复杂的术语有什么看法?为了帮助解决这个问题,我们需要知道您所阅读的内容,这些内容似乎让您感到困惑。
<小时/> 您还没有显示任何上下文代码,所以让我们构建一些上下文来帮助理解这一点。我将选择将一个点定义为
point(X, Y)
,并将一行显示为point(X, Y)
,其中line(P1, P2)
和P1
为点。因此,我也可以将行表示为P2
。这是我作为程序员的选择。
如何在Prolog中定义有效点?我可以用术语line(point(X1, Y1), point(X2, Y2))
来定义它。但point(X, Y)
和X
是什么?他们怎么定义?我可能会强制他们是数字。所以这是一个有效Y
的规则:
point
在Prolog中我可以简化一下,因为我可以使用复杂的术语作为子句的头部:
valid_point(P) :-
P = point(X, Y), % a Point looks like point(X, Y)
number(X),
number(Y).
如果valid_point(point(X, Y)) :-
number(X),
number(Y).
和valid_point(point(X, Y))
都是数字,那么X
只会成功。如果您要问Prolog如果Y
是一个有效点(查询(point(3, 5.2)
,那么它会成功(例如&#34; true&#34;)。如果您要问Prolog是否{{1} }是一个点(查询valid_point(point(3, 5.2)).
,它会失败(说&#34;假&#34;)。
现在让我们定义一条线。一条线由任意两点定义,因此我们可以将其表示为point(a, 3)
一词,其中valid_point(point(a, 3)).
和line(P1, P2)
是不相同的有效点。因此,我们可以如下定义有效行。我将详细说明如何统一和使用术语:
P1
再次,Prolog让我使用复合术语来进一步简化:
P2
此规则表明valid_line(Line) :-
Line = line(P1, P2),
P1 = point(X1, Y1), % P1 is a valid point
valid_point(P1),
P2 = point(X2, Y2), % P2 is a valid point
valid_point(P2),
( X1 =\= X2 ; Y1 =\= Y2 ).
和valid_line(line(point(X1, Y1), point(X2, Y2))) :-
valid_point(point(X1, Y1)),
valid_point(point(X2, Y2),
( X1 =\= X2 ; Y1 =\= Y2 ).
形成有效行,如果它们是有效点,且point(X1, Y1)
和point(X2, Y2)
不相等,或X1
}和X2
不相等。
让我们继续更高层次的规则。如果线条有效并且其点具有相同的横坐标,则线条垂直。我们可以创建一个规则,Y1
如果行参数是垂直的则成功,否则失败:
Y2
我们可以通过统一条款开头的横坐标来缩写:
vertical_line
在上述所有示例中,我将规则名称与数据结构名称分开。所以我通常vertical_line(line(point(X1, Y1), point(X2, Y2)) :-
valid_line(line(point(X1, Y1), point(X2, Y2)),
X1 = X2.
,但vertical_line(line(point(X, Y1), point(X, Y2))) :-
valid_line(line(point(X, Y1), point(X, Y2)).
代表一条线的结构。没有理由他们必须分开,但它可以帮助避免混淆,如果他们是。即使它们是相同的,Prolog是否作为查询执行它将取决于上下文。例如,我可以定义一个规则valid_line/1
,只有当参数是数字时才能成功:
line/2
然后我可以查询:
point/2
但是,如果我然后定义point(X, Y) :-
number(X),
number(Y).
:
?- point(1, 3).
true
?- point(a, 7).
false.
执行统一line/2
时,这不会强制执行有效点(不调用line(P1, P2) :-
P1 = point(X1, Y1),
P2 = point(X2, Y2),
( X1 =\= X2 ; Y1 =\= Y2 ).
)。这是因为Prolog中的谓词不是函数,并且不会那样。如果我要查询,point/2
它可能会产生错误,因为我试图用数字与P1 = point(X1, Y1)
比较坐标。表达式line(point(a, 3), point(c, d))
实际上是Prolog中的术语(=\=)/2
。正如我上面提到的,当Prolog进行呼叫时,它位于顶级术语,在这种情况下是P1 = point(X1, Y1)
,而'='(P1, point(X1, Y1))
是&#34;只是一个术语&#34;并没有在这种背景下调用。我可以拨打'='
但如下:
point(X1, Y1)
然后Prolog会更优雅地检查点的有效性(根据我定义的point/2
谓词)。但我并不认为这与单独定义line(P1, P2) :-
P1 = point(X1, Y1),
call(P1),
P2 = point(X2, Y2),
call(P2),
( X1 =\= X2 ; Y1 =\= Y2 ).
谓词一样清晰。
答案 2 :(得分:0)
在一个术语中,变量按名称唯一。所以,事实
vertical(line(point(X,Y),point(X,Z))).
仅根据P1,P2的ascissa的身份说明未解释的术语(line(P1,P2)
)的属性。
现在,如果这有任何意义,它与特定的应用领域有关,但我们对此一无所知,排除了平庸的几何直觉......