Un "lenguaje de inteligencia artificial" diferente Prolog

¡En el top 20 de las clasificaciones de TIOBE recién publicadas en agosto, apareció el antiguo lenguaje de inteligencia artificial Prolog!

TIOBE 说到:“Y, lo que es aún más sorprendente, vemos que Prolog vuelve a entrar en el top 20 después de 15 años... haciendo una reaparición inesperada”.

Índice TIOBE de agosto de 2021

(Imagen vía TIOBE Index de agosto de 2021)

Después de un lapso de más de diez años, este lenguaje único ha vuelto a aparecer frente a todos, ocupando el segundo lugar después de Go! ¡No es demasiado pronto para aprender!

Si no puede aprenderlo, siga mis pasos. Hoy, comenzaremos con un ejemplo fresco y refinado para apreciar este "lenguaje de inteligencia artificial" diferente.

Además, también hemos hecho un video introductorio de Prolog que acompaña a este artículo, lo invitamos a verlo. Si el video te es útil, no olvides hacer clic en tres enlaces :)

www.bilibili.com/video/BV14A…

(Realmente es agotador hacer videos. Desde el guión hasta la música y la edición, lo hice todo yo solo. Por favor, apóyenme :)

Prólogo

like(mercury, kathy).        % mercury 喜欢 kathy。
like(kathy, mercury).        % kathy 喜欢 mercury。

lover(X, Y) :- like(X, Y), like(Y, X).        % 如果X喜欢Y,且Y也喜欢X,则X与Y是恋人。


询问mercury和谁是恋人:lover(mercury, Who).
电脑告诉我 Who = kathy,

这就是Prolog!
复制代码

(Este texto está tomado de una posición destacada en la página de inicio del Foro Chino de Idiomas de Inteligencia Artificial de Prolog , un antiguo sitio web que todavía existe en la actualidad )

¡Este es un poema que invita a la reflexión! Pero puede ser difícil para usted imaginar que esto es en realidad un "lenguaje de programación".

Mirando hacia atrás en el desarrollo de los lenguajes de programación, hay varios períodos.

  • El lenguaje de programación de primera generación: lenguaje de máquina, usando 0 y 1 para escribir código (la habilidad mágica perdida hace mucho tiempo que Weld Wudi nos mostró).
  • Lenguaje de programación de segunda generación: lenguaje ensamblador
  • Lenguajes de programación de tercera generación: lenguajes de alto nivel, representativos de C, Java, C++, C#
    • 3.5 GL: La tercera generación tardía, como Python, Lisp 1 , tiene un mayor grado de abstracción y ya tiene la sombra de la cuarta generación.
  • Lenguaje de programación de cuarta generación: mayor nivel de abstracción, no para tratar con detalles relacionados con el hardware, centrarse en describir problemas y resolver problemas, como SQL, MATLAB

Tal vez la comprensión de los pequeños amigos sobre los lenguajes de programación se detenga aquí. Pero en realidad lo teníamos hace décadas—

  • 第五代编程语言:人工智能语言,这一代编程语言期望计算机能自动求解问题,基于问题所给定的某些限制,交由程序来处理而不需以程序员再投入人力开发程序。

今天说「人工智能」你肯定想到 Python,但 Python 并不是第五代的人工智能语言。而 Prolog 就是这种没落十余年的第五代编程语言之一。

今天我们的重点不是谈为什么第五代编程语言集体没落,而是来学习这种上古语言 Prolog。

Prolog

Prolog 这个词来自 PROgramming of LOGic,也就是逻辑编程的意思。Prolog 不需要你编写程序运行过程,你只要给出事实和规则,它会自动分析其中的逻辑关系。然后你就可以通过查询,让 Prolog 完成复杂的逻辑运算。

SWI-Prolog

Prolog 有非常多的实现,维基百科甚至专门有个词条比较不同的 Prolog 实现:

这里我们采用 SWI-Prolog——一个十分完善、仍在开发、维护的开源实现。在 macOS 中,可以用 brew 安装 SWI Prolog:

$ brew install swi-prolog
复制代码

Debian 系 Linux 也可以用 apt-get 来轻松完成安装。其他系统可以去 官网下载页 寻找对应的二进制文件或者从源码构建。

如果你不想或难以完成安装,SWI-Prolog 还为你准备了 在线版本

安装完成之后,通过 swipl 命令进入一个和 Python 类似的 SWI-Prolog REPL 环境(SWI-Prolog 的提示符是 ?-):

$ swipl
?- 
复制代码

国际惯例,先写 Hello World:

?- write('Hello, World!').
Hello, World!    % write 打印的结果
true.            % 返回值
复制代码

注意 Prolog 的语句最后以 . 结尾。

要退出 SWI-Prolog,可以摁 Control-D 或输入 halt.。(你可以通过键入 apropos(quit). 来找到关于“退出”的主题 halt,然后用 help(halt). 查看如何退出)

Prolog 基础语法

与我们平时接触的其他基于变量的编程语言不同,Prolog 的基础是

  • Facts:事实
  • Rules:规则
  • Queries:查询

这几个概念就是字面意思,如

  • 事实:11 不能被 2 整除。
  • 规则:不能被 2 整除的数是奇数。
  • 查询:11 是奇数吗?
    • 结果(答案):11 是奇数。

在 Prolog 中事实规则和在一起组成了知识库(Knowledge base),我们把这两者写在后缀名为 .pl 的文件里。

查询写在 REPL 中,基于已知知识库,对某个问题进行逻辑推理,给出答案。

事实

例如,假定我们知道一些事实(字面意思)是:

  • Yomogi 和 Yume 相互喜欢;
  • Kaneishi 也喜欢 Yomogi。

在 Prolog 中,这些个事实表示为:

like(yomogi, yume).
like(yume, yomogi).
like(kaneishi, yomogi).
复制代码

我们可以把这个写到一个 ./ssss.pl 文件中,但不能写在 REPL 里。

在 Prolog 中,小写字母开头的单词是常量,表示一个对象,如 likemercurykathy 都不需要预先定义,不需要赋值,直接写即可。

注意,喜欢这种事情是单向的。A 喜欢 B 不代表 B 喜欢 A(如 kaneishi 与 yomogi),所以这里为了表示 yomogi 与 yume 相互喜欢,必须写两句。

我们把 like 称为一种关系,即代表两个或多个对象之间某种相互联系,我们还可一定义只与一个对象有关的事实,这种事实称为属性

male(yomogi).
female(yume).
female(kaneishi).
复制代码

规则

现在我们制订一个规则:

  • 如果 X 喜欢 Y,且 Y 也喜欢 X,则 X 与 Y 就是恋人。

规则在 Prolog 表示为 head :- goals,即 goals 成立时,head 也就成立。

lover(X, Y) :- like(X, Y), like(Y, X).
复制代码

(这行代码也写到 ./ssss.pl 中)

这行代码表示,如果 like(X, Y)like(Y, X) 都成立,则有 lover(X, Y) 成立。用 Python 语言表示就是:

def lover(X, Y):
    return like(X, Y) and like(Y, X)
复制代码

在 Prolog 中的或与非:

  • A, B 表示「A B」
  • A; B 表示「A B」
  • \+ A 表示「 A」

查询

前面的事实和规则都是定义,就是我们告诉 Prolog 一些已知信息。查询才是重头戏,就是让 Prolog 帮我们做逻辑题目。

使用 swipl 命令进入 Prolog 环境,然后使用 consult("path/to/xxx.pl") 加载写在 .pl 文件中的代码,来读取已知条件:

$ swipl
Welcome to SWI-Prolog (threaded, 64 bits, version 8.2.4)
?- consult('ssss.pl').
true.
复制代码

或者,也可以用 [xxx]. 这个语法来加载 xxx.pl

然后,如果我们想知道 yomogi 是否喜欢 yume,就可以问 Prolog:

like(yomogi, yume).
true.
复制代码

结果 true 表示 like(yomogi, yume) 即 yomogi 喜欢 yume 成立。而:

?- like(yomogi, kaneishi).
false.

?- like(yomogi, gauma).
false.
复制代码

false 就说明 yomogi 不喜欢 kaneishi,当然纯情的 yomogi 更不可能喜欢我们没定义过的陌生人 gauma。

前面这几次查询都是询问某个关系是否成立,也就是看看某个「事实」是否存在。而结合已定义 lover 的规则,Prolog 还可以:

?- lover(yomogi, yume).
true.

?- lover(yume, yomogi).
true.

?- lover(yomogi, kaneishi).
false.

?- lover(kaneishi, yume).
false.
复制代码

通过已知的 like 关系(事实),结合我们给的 lover 定义(规则),Prolog 可以推理:

  • yomogi 和 yume 是恋人。当然,反过来说“yume 和 yomogi 是恋人”同样成立。
  • 因为 yomogi 不喜欢 kaneishi,所以 yomogi 和 kaneishi 不是恋人!
  • yume 和 kaneishi 之间没有任何一方喜欢的关系,所以两人也不是恋人。

如果只是这样,只会判断个对错,那 Prolog 就太弱了。在 Prolog 查询中还可以使用变量

例如,我们想要知道 yomogi 喜欢谁(Who)?就可以问 Prolog:

?- like(yomogi, Who).
Who = yume.
复制代码

这里 Who 是一个变量,Prolog 会求解查询中的变量,这里得到的结果是 Who = yume,也就是说 yomogi 喜欢 yume。

这里 Prolog 所做的操作其实就是解个方程,得到使查询结果为真的变量值:like(yomogi, Who) = true 得到 Who=?

Prolog 中大写字母开头的单词是变量。(注意,Prolog 中变量大写、常量小写,和我们通常的 C 语言编程习惯是反的。)如果写错了大小写,意思就不对了,尝试查询:

?- like(yomogi, who).
false.    % yomogi 不喜欢 who 这个人,咱也不知道 who 是谁
复制代码

如果我们要查询 「yume 是否喜欢 yomogi」,而把 yume 写成了大写的 Yume,就变成了查询「喜欢 yomogi 的人是谁」:

?- like(Yume, yomogi).    % Yume 是个变量,不是 yume 这个人
Yume = yume ;             % 摁 tab 键或摁 ; 键显示下一个结果
Yume = kaneishi.
复制代码

这里 Yume 等于 Who,只是个变量,表示喜欢 yomogi 的人,而不是南同学前面定义中的 yume 这个人。根据我们一开始定义的事实,yume 和 kaneishi 都喜欢 yomogi,所以这里 Yume (Who)就可以是 yume 或 kaneishi。

对于这种有多个结果的查询。SWI-Prolog 默认每次只显示一个结果,然后等待,我们需要摁下 ; (表示「或」,还记得吗)然后再显示下一个结果。(这里也可以摁 tab 键)

这里还想补充一点,Prolog 中有一个很有用的谓词 listing,可以列出某种关系的全部事实,或查看规则的定义:

?- listing(like).
like(yomogi, yume).
like(yume, yomogi).
like(kaneishi, yomogi).
    
?- listing(lover).
lover(X, Y) :-
    like(X, Y),
    like(Y, X).
复制代码

例:苏格拉底会不会死?

利用前面这些知识,就可以解决很多逻辑问题了,例如,已知:

  • 苏格拉底是人
  • 人都会死

所以可以退出结论:苏格拉底会死。

用 Prolog 来解决这个问题:

person(socrates).       % 事实
mortal(X) :- person(X). % 规则

---
% 查询

?- mortal(socrates).    % 苏格拉底会死吗
true.
    
?- mortal(X).           % 谁会死
X = socrates
复制代码

如果你觉得一个完整的程序不能只包括逻辑运算部分,还必须拥有输入输出,那么,结合 hello world 中的 write,我们可以实现:

person(socrates).
person(plato).
person(aristotle).

mortal(X) :- person(X).

mortal_report :- 
    write('Known mortals are:'), nl, mortal(X), write(X), nl.  % nl 是换行
复制代码

然后再解释器中调用:

?- mortal_report.
socrates
plato
aristotle
复制代码

这就得到了一些生命有限的凡人。

利用这种「逻辑编程」你还可以写成更多有趣的例子。如果你觉得这个例子已经理解不能了,那我推荐你重新学习一下基础的《数理逻辑》(很多《离散数学》书的第一章)。


到这里,我们其实只是看到了 Prolog 的最简单的用法,但完全没有接触到 Prolog 中真正强大的地方,例如递归,这些就写另一篇更深入的文章来进一步学习了,——不过我们现在这篇文章到此就结束了。

参考

[1] Blackburn, Patrick and Bos, Johan and Striegnitz, Kristina. Learn Prolog Now!. College Publications. 2006

[2] 阮一峰. Prolog 语言入门教程. 阮一峰的网络日志. 2019

[3] SWI Prólogo. Primeros pasos

[4] Draveness. Fundamentos de Prolog <1> . draveness.me, 2015

[5] Autor desconocido. Prólogo tutorial introductorio. Pescar y escuchar Zhuxuan. 2004

(El último artículo fue un artículo que leí cuando estaba aprendiendo Prolog hace casi 10 años. Fue muy fácil de entender. Pero ahora solo hay múltiples reimpresiones de este artículo y la traducción original al inglés de este artículo en Internet. Es Es difícil encontrar esta preciosa traducción al chino. En este momento, acabo de descubrir que puede ser de un sitio web llamado Ding Diao Ting Zhu Xuan, pero este sitio web está cerrado y las copias de seguridad en archive.org tienen errores 3xx. Haré más. arqueología cuando tengo tiempo)


  1. Lisp: Algunas fuentes dicen que Lisp es un lenguaje de programación de quinta generación, pero según el Lisp que he aprendido, Lisp no está de acuerdo con la definición de quinta generación, pero el lenguaje de quinta generación se puede implementar con Lisp.

Supongo que te gusta

Origin juejin.im/post/6993707906398945287
Recomendado
Clasificación