prolog

随便说说

最近在写gerrit的rules.pl,一开始我以为是perl语言,看了文档才发现这个是prolog语言,于是,就搜文档看看,这个语言的思路和平常的开发语言很不一样,很清奇

一个例子

1
2
3
4
5
6
7
% 表示love(X,Y)为true,语句以.结尾,X -> love -> Y,这个是单向的,不能理解成Y->love->X
love(X,Y).

% 表示当love(X,Y)为true、且love(Y,X)为true的时候,lovers(X,Y)为true,右边是左边的充要条件
lovers(X,Y):-love(X,Y),love(Y,X).

%

一些理解

  • prolog程序没有特定的运行顺序,其运行顺序是由电脑决定的,而不是编程序的人。
  • prolog的原理就是关系数据库,它是建立在关系数据库的基础上的。
  • 强大的递归功能

知识点

事实

事实(facts)是prolog中最简单的谓词(predicate)。它和关系数据库中的记录十分相似。

语法结构如下 pred(arg1, arg2, … argN).

其中pred为谓词的名称。arg1,…为参数,共有N个。

参数可以是以下四种之一:

  1. 整数(integer)
  2. 原子(atom) 由小写字母开头的字符串。
  3. 变量(variable) 由大写字母或下划线(_)开头。
  4. 结构(structure)

可以将事实理解成,向数据库里面写数据。

常用的内部谓词

  1. write/1 把参数当作字符串输出到屏幕
  2. nl/0 在屏幕上输出回车
  3. tab/1 输出n个空格
  4. not/1 取反
  5. =/2 此谓词当它的两个参数能够联合时成功,反之则失败。它的语法如下:

规则

pred(x):- pred(Y),pred(Z).

前面我们已经说过,谓词是使用一系列的子句来定义的。以前我们所学习的子句是事实,现在让我们来看看规则吧。规则的实质就是储存起来的查询。它的语法如下:

head :- body 其中,

head 是谓词的定义部分,与事实一样,也包括谓词名和谓词的参数说明。 :- 连接符,一般可以读作‘如果’。 body 一个或多个目标,与查询相同。

数学计算

X is <数学表达式>

1
2
3
4
5
X is 3*(1+2).
X > Y
X < Y
X >= Y
X =< Y

= 时赋值不计算, is 计算 而=:=是两头都计算

结构

functor(arg1,arg2,…)

类似于结构体

1
location_s(object(candle, red, small, 1), kitchen).

联合

变量&任何项目: 变量可以与任何项目绑定,其中也包括变量 原始项目&原始项目: 两个原始项目(原子或整数)只有当它们相同时才能联合。 结构&结构: 如果两个结构的每个相应的参数能联合,那么这两个结构可以联合。

=(arg1, arg2)

为了方便阅读,也可以写成如下形式:

arg1 = arg2

列表

list [a,b,c] [X|Y] X 是列表头(head), 它可以是一个列表,或其他任何数据结构 Y 是列表尾(tail), 它只能可以是一个列表

gerrit

gerrit中的设置submit的规则时,需要设置成,至少有一个+2,并且总分是4分及以上才能submit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
sum_list([], 0).
sum_list([H | Rest], Sum) :- sum_list(Rest,Tmp), Sum is H + Tmp.

% 这部分是统计2的个数
count_twos([], 0). % 初始条件
count_twos([2|T], N) :- count_twos(T, N1), N is N1 + 1. % 动态规划之表第一个元素是2
count_twos([H|T], N) :- H \= 2, count_twos(T, N). % 动态规划之表第一个元素不是2


add_category_min_score(In, Category, Min,  P) :-
    findall(X, gerrit:commit_label(label(Category,X),R),Z),
    count_twos(Z, Twos), % 统计2的个数
    Twos >= 1, % 如果打分列表中的2的个数大于1,即至少有一个2
    sum_list(Z, Sum),
    % member(2, Z),!,member没法直接用,这里会报错
    Sum >= Min, !,
    gerrit:commit_label(label(Category, V), U),
    V >= 1,
    !,
    P = [label(Category,ok(U)) | In].

add_category_min_score(In, Category,Min,P) :-
    P = [label(Category,need(Min)) | In].

submit_rule(S) :-
    gerrit:default_submit(X),
    X =.. [submit | Ls],
    gerrit:remove_label(Ls,label('Code-Review',_),NoCR),
    add_category_min_score(NoCR,'Code-Review', 4, Labels),
    S =.. [submit | Labels].

通过以上例子发现,prolog语言实际上非常适合用来实现动态规划,简直是完美符合