问题描述
我注意到在一些 Prolog 程序中使用了操作符 ->,但我不知道它的含义.这是它的使用示例:
swish_add_user(用户、密码、字段):-短语("$1$", E, _), % 使用 Unix MD5 哈希地穴(密码,E),string_codes(哈希,E),条目 = passwd(用户,哈希,字段),绝对文件名(swish(密码),文件,[访问(写入)]),(存在_文件(文件)->http_read_passwd_file(文件,数据);数据 = []),( selectchk(passwd(User, _, _), Data, Entry, NewData)->真的;附加(数据,[条目],新数据)),http_write_passwd_file(文件,新数据).
它在这个子句中的用途是什么?什么时候应该使用这个运算符,什么时候不应该?
PS:代码段取自authenticate.plswish 存储库中的 文件,Prolog IDE 在线.
Joel76 的回答给出了 ->/2
控件构造的最常见用法,该构造定义在ISO 序言.Goal1 -> 的描述GNU Prolog 手册 中的目标 2
是:
Goal1 ->Goal2
首先执行 Goal1
,如果成功,则删除由 Goal1
创建的所有选择点并执行 Goal2
.这个控制结构就像一个 if-then(Goal1
是测试部分,Goal2
是 then 部分).请注意,如果 Goal1
失败 ->/2
也会失败.->/2
经常与 ;/2
结合来定义一个 if-then-else 如下: 目标1 ->目标2;目标 3
.请注意,Goal1 ->Goal2
是 (;)/2
的第一个参数,Goal3
(else 部分)是第二个参数.这样的 if-then-else 控制结构首先为 else 部分(直观地与 ;/2
相关联)创建一个选择点,然后执行 Goal1
.在成功的情况下,由 Goal1
创建的所有选择点以及 else-part 的选择点都将被删除并执行 Goal2
.如果 Goal1
失败,则执行 Goal3
.
它不像 数学逻辑蕴涵(正如其符号形式所暗示的那样),因为在这样的蕴涵子句中,F ->;T
为真,而在 Prolog 中,如上所述,如果 Goal1
失败,则 ->/2
表达式失败.
在这种情况下,注意运算符的优先级很重要.在 Prolog 中,优先顺序是 ,
,然后是 ->
,然后是 ;
.因此,如描述中所述,在 if-then-else 构造中,Goal1 ->;目标2;Goal3
,Goal1 ->Goal2
表达式是 ;/2
的第一个参数.以下是各种情况下会发生的情况:
Goal1 ->目标2;Goal3 if-then-else 注释----- ----- ----- ------------ -----成功 成功 NE* 成功 目标 1 选择点已移除目标 2 选择点仍然存在(如果存在)成功 失败 NE 失败 Goal1 选择点被移除失败 NE 成功 成功 Goal3 选择点仍然存在(如果存在)失败 NE 失败 失败*NE = 未执行
由于优先级的原因,if-then-else 构造通常带有括号,如示例中所示:
( selectchk(passwd(User, _, _), Data, Entry, NewData)->真的;附加(数据,[条目],新数据)),胡说八道
如果括号不存在,那么 blah-blah
将成为 else 的一部分,如果 selectchk
成功则不会执行.p>
选择点也发生了一些有趣的事情.如果 Goal1
成功,Prolog 将调用 Goal2
等,但不会为 Goal1
回溯到更多解决方案(如果存在).举例说明:
a(1).a2).测试 :-(一(X)->写(X),NL;写('没有'),NL).|?- 测试.1是的
在上面,Prolog没有回去找a(X)
的X = 2
.另一方面,else
可能会发生回溯:
foo :-( 错误的->write('不会发生'), nl;斧头),写(X),NL).|?- 富.1真的 ?;2是的
Goal2
也会发生回溯:
foo :-( 真的->a(X), 写(X), nl;写('其他'),NL).|?- 富.1真的 ?;2是的
但正如您所见,一旦选择了 Goal2
路径,当解决方案 else
(Goal3
)code>Goal2 已用尽.A 可能是预期的,Goal2
与 Goal3
的执行是互斥的,具体取决于 Goal1
的结果.
I have noticed the use of the operator -> in some Prolog programs, but its meaning is unknown to me.This is an example of its use:
swish_add_user(User, Passwd, Fields) :-
phrase("$1$", E, _), % use Unix MD5 hashes
crypt(Passwd, E),
string_codes(Hash, E),
Entry = passwd(User, Hash, Fields),
absolute_file_name(swish(passwd), File,
[access(write)]),
( exists_file(File)
-> http_read_passwd_file(File, Data)
; Data = []
),
( selectchk(passwd(User, _, _), Data, Entry, NewData)
-> true
; append(Data, [Entry], NewData)
),
http_write_passwd_file(File, NewData).
What is its use in this clause? When should I use this operator and when not?
PS: The code segment is taken from the authenticate.pl file in the swish repository, an excellent implementation of a Prolog IDE online, by the way.
Joel76's answer gives what is probably by far the most common usage of the ->/2
control construct, which is defined in ISO Prolog. The description given for Goal1 -> Goal2
in the GNU Prolog manual is:
It doesn't act like a mathematical logical implication (as its symbolic form might suggest) because, in such an implication clause, F -> T
is true, whereas in Prolog, as mentioned above, if Goal1
fails, then the ->/2
expression fails.
It's important to note operator precedence in this case. In Prolog, the order of precedence is ,
, then ->
, then ;
. Thus, as stated in the description, in an if-then-else construct, Goal1 -> Goal2 ; Goal3
, the Goal1 -> Goal2
expression is the first argument of ;/2
. Here is what happens in various cases:
Goal1 -> Goal2 ; Goal3 if-then-else Notes
----- ----- ----- ------------ -----
Succeeds Succeeds NE* Succeeds Goal1 choice point removed
Goal2 choice point remains (if it exists)
Succeeds Fails NE Fails Goal1 choice point removed
Fails NE Succeeds Succeeds Goal3 choice point remains (if it exists)
Fails NE Fails Fails
*NE = not executed
Because of the precedence, the if-then-else constructs are often parenthesized, as in the example:
( selectchk(passwd(User, _, _), Data, Entry, NewData)
-> true
; append(Data, [Entry], NewData)
),
blah-blah
If the parentheses were not there, then blah-blah
would become part of the else and not executed if selectchk
succeeds.
There is also something interesting that happens to the choice points. If Goal1
succeeds, Prolog will call Goal2
, etc, but won't backtrack to more solutions, if they exist, for Goal1
. To illustrate:
a(1).
a(2).
test :-
( a(X)
-> write(X), nl
; write('no a'), nl
).
| ?- test.
1
yes
In the above, Prolog didn't go back to find X = 2
for a(X)
. On the other hand, backtracking can occur for the else
:
foo :-
( false
-> write('not gonna happen'), nl
; a(X),
write(X), nl
).
| ?- foo.
1
true ? ;
2
yes
Backtracking also occurs for Goal2
:
foo :-
( true
-> a(X), write(X), nl
; write('else'), nl
).
| ?- foo.
1
true ? ;
2
yes
But as you can see, once the Goal2
path is chosen, there's no backtracking to the else
(Goal3
) when solutions for Goal2
are exhausted. A might be expected, executions of Goal2
versus Goal3
are mutually exclusive depending upon the result of Goal1
.
这篇关于Prolog运算符'->'是什么意思的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!