正如所指出的,Prolog 不能很好地映射到程序性思维。
我找到了将 Prolog 程序及其“数据库”视为树(森林?)的最佳方式。这个类比有点粗略,因为图包含循环(递归)。
当您要求 prolog 引擎确定特定断言(谓词)的真假时,它开始使用统一(模式匹配)对树进行深度优先、从左到右的遍历来指导遍历。当遍历到达叶节点时,谓词为true
。在回溯时,它... 回溯并继续树行走。当没有更多可到达的叶节点时,谓词失败。
Prolog 是一种描述性语言:您用谓词演算来描述成功的条件。然后,您只需让 Prolog 的推理引擎找到适用的解决方案。如果你试图将程序性的、命令式的思想硬塞到模型中,除了让事情变得比原本应该的更困难之外,根据我的经验,你几乎可以保证性能不佳。
我发现 Leon Sterling 和 Eliot Shapiro 的教科书The Art of Prolog比 Clocksin & Mellish 的Programming in Prolog更有价值,更有启发性和启发性。
编辑注意:您的示例谓词
pred(X) :-
X = 1 -> do this , ! ; else do that ,
write('x =/= 1')
.
有一些问题。
首先,就像 C 或 C# 或其他过程语言一样,and
andor
运算符具有不同的优先级,因此表达式 likeif ( a && b || c && d ) ...
可能不会像您认为的那样绑定,由于运算符优先级,您的示例谓词可能没有按照您的想法执行做:如所写,它绑定为
pred(X) :-
X=1 ->
( do_this , ! )
;
( do_that , write( 'x =/= 1' ) )
.
当你可能想要的是
pred(X) :-
( X=1 ->
( do_this , ! )
;
do_that ,
) ,
write( 'x =/= 1' )
.
您需要使用括号来明确您的预期绑定:
pred(X) :-
( X=1 ->
( do_this , ! )
;
do_that
),
write('x =/= 1')
.
此外,!
您的示例中的 cut ( ) 是不必要的,因为蕴含运算符的->
行为就像涉及到一个 cut 一样。这个:
foo(X) :-
truthy(X) ->
writeln('truthy!')
;
writeln('falsy')
.
几乎完全一样
foo(X) :- truthy(X) , ! ,
writeln( 'truthy' ) .
foo(_) :- writeln( 'falsy' ) .
第三,你应该在头部使用统一和模式匹配。忽略write/1
,您的示例可能更有意义
pred(1) :- do_this , ! .
pred(X) :- do_that .
一般来说,如果你正在学习序言,我会说避免使用隐含运算符(和交替(逻辑 OR,';'/2
)。更喜欢带有多个子句的显式谓词来表达选择。而不是类似的东西
foo(X) :- ( try_this(X) ; try_that(X) ; finally(X) ) .
更喜欢
foo(X) :- try_this(X) .
foo(X) :- try_that(X) .
foo(X) :- finally(X) .
而不是暗示:
foo(X) :- X=1 -> try_this(X) ; try_that(X) .
喜欢这样的东西:
foo(1) :- ! , try_this(X) .
foo(X) :- try_that(X) .
我认为它更容易理解正在发生的事情,因为它使选择点(及其消除)明确。