Prolog 不是在写“执行步骤”,而是在定义知识库(Knowledge Base)和逻辑关系,然后让解释器去通过**深度优先搜索(DFS)和回溯(Backtracking)**来寻找证明。
这里是一份针对程序员的 Prolog 速成指南:
1. 核心概念:只有三种元素
在 Prolog 里,一切都是 Term(项):
- 原子(Atom):常量,小写开头。例如:
cat,justin,'Hello World'。 - 数字(Number):
1,3.14。 - 变量(Variable):大写开头或下划线开头。例如:
X,List,_(匿名变量)。- 注意:变量没有“赋值”的概念,只有“绑定(Binding)”的概念。一旦绑定,在这个作用域内不可变。
- 结构(Structure/Compound Term):
functor(arg1, arg2)。例如:parent(john, mary)。
2. 程序的构成:事实与规则
Prolog 程序 = 事实 + 规则。
事实 (Facts)
永远为真的陈述。
human(socrates).
parent(john, mary).
parent(mary, tom).
规则 (Rules)
类似“如果...那么...” (Horn Clauses)
格式:Head :- Body. (如果 Body 成立,则 Head 成立)。
% 如果 X 是 Y 的父母,且 Y 是 Z 的父母,那么 X 是 Z 的祖父母
grandparent(X, Z) :-
parent(X, Y),
parent(Y, Z).
3. 执行机制:统一 (Unification) 与 回溯
这是你最需要理解的部分。
Unification (=)
这不是赋值,是模式匹配。Prolog 试图让等号两边变得一样。
X = 10.-> X 被绑定为 10。10 = 10.-> True。10 = 5.-> False。foo(X, a) = foo(b, Y).-> 成功,X 绑定为 b,Y 绑定为 a。3 + 2 = 5.-> False! (左边是结构+(3,2),右边是数字 5,它们长得不一样)。
算术求值 (is)
如果你想算数,必须用 is。
X is 3 + 2.-> X 绑定为 5。
回溯 (Backtracking)
当 Prolog 遇到死胡同(fail)时,它会退回到上一个决策点(choice point),尝试另一种可能性。
4. 数据结构:列表 (List)
Prolog 的列表是链表结构。
- 空表:
[] - 非空表:
[Head | Tail]Head是第一个元素。Tail是剩下的列表。
解构示例:
[a, b, c] 可以写成 [a | [b, c]]。
查询:[H|T] = [1, 2, 3].
结果:H = 1, T = [2, 3].
5. 递归模式(最常用的模板)
Prolog 没有 for 或 while 循环,一切靠递归。
模板:
- Base Case(基准情况):通常是空表或 0。
- Recursive Step(递归步骤):处理头部,递归尾部。
例子:计算列表长度
% 1. 基准:空表长度为 0
len([], 0).
% 2. 递归:列表长度 = 尾部长度 + 1
len([_|T], N) :-
len(T, SubN), % 先递归算出尾部的长度
N is SubN + 1. % 再加 1 (注意不能写 N = SubN + 1)
例子:列表拼接 (append).这是 Prolog 最神奇的代码之一,既能拼接,能拆分。
% base: 空表拼接 L,结果就是 L
my_append([], L, L).
% recursive: [H|T] 拼接 L2,结果是 [H|Result]
% 只要 T 和 L2 拼成了 Result
my_append([H|T], L2, [H|Result]) :-
my_append(T, L2, Result).
- 拼接:
my_append([1,2], [3], X).->X=[1,2,3] - 逆向拆分:
my_append(X, Y, [1,2,3]).-> Prolog 会列出所有可能的 X 和 Y 组合!
6. 程序员常见的坑 (Gotchas)
=vsisX = 3+2结果是3+2(一个表达式结构)。X is 3+2结果是5(数值)。
- 单例变量警告 (Singleton Variable)
- 如果你定义了
member(X, [H|T])但没用到H,Prolog 会警告。 - 修正:用下划线
_代替没用的变量,如member(X, [_|T])。
- 如果你定义了
- 截断符
!(Cut)- 告诉 Prolog:“到这里为止,前面的匹配不要再回溯了”。
- 用于优化(剪枝)或强制互斥(如
max函数)。
总结练习
用一句话概括 Prolog 编程:“不要告诉电脑怎么做(How),告诉它什么是真的(What),以及定义好递归的基准条件。”