上一篇对Prolog有了一个感性的认识,今天介绍下Prolog中一些基本概念,想要用Prolog解决一些实际问题之前必须要先了解它们。这些概念在《七周七语言》这本书中都有介绍,我简单提炼汇总下,就当给这门小众语言做个宣传吧。

变量/规则/知识库

在Prolog中变量的命名是有特殊要求的,如果一个词以小写字母开头,它就是一个原子(atom),类似于其他语言中的符号(symbol),如果一个词以大写或下划线开头,那么它就是一个变量,和其他语言一样变量值可以改变,可以赋值(不过更灵活)。

符号组成一些事实:

likes(zhangsan,lisi).
likes(wangwu,lisi).
likes(chenliu,maqi).

符号和变量在一起可以用来定义规则:

friend(X,Y):- \+(X = Y),likes(X,Z),likes(Y,Z).

事实是我们对这个世界直接观察的结果。规则是关于现实世界的逻辑推论。

事实 + 规则 = 知识库

上面的规则可以叫做friend/2因为它有两个参数(类似C#方法中的形参),:-读作“如果”,“如果”后面是由一系列“子目标”组成,子目标之间可以是且的关系,用“,”分割,也可以是或者的关系,用“.”表示。Prolog就是通过验证规则来回到我们yes或no的,如果参数能满足所有子目标就是yes。

合一(unification)

 合一是Prolog中一个非常重要的概念。简单的来说合一就相当于其它语言中的赋值:

cat(lion).
cat(tiger). dorothy(X,Y,Z) :- X = lion,Y = tiger,Z = bear.
twin_cast(X,Y) :- cat(X),cat(Y).

合一的意思是:找出那些使规则匹配的值。

所以执行dorothy(lion,tiger,bear).这句,Prolog会返回yes:

dorothy/3规则的右侧,Prolog将lion赋值给X,tiger赋值给Y,bear赋值给Z,就像在命令式语言中这样:

var X = lion;
var Y = tiger;
var Z = bear;

这些值和左侧(也就是dorothy(lion,tiger,bear))对应的值相匹配,所以合一成功。

不过真正让合一发挥作用的是因为它在规则的两侧都能工作,在GNU Prolog中执行下面的语句:

dorothy(One,Two,Three).

会得到这样的结果:

在规则右侧Prolog还是分别将X,Y,Z和lion,tiger,bear进行绑定,而在规则的右侧,Prolog是的One,Two,Three分别和X,Y,Z进行合一了:

One = X = lion;
Two = Y = tiger;
Three = Z = bear;

并且合一的情况有时候不是唯一的,我们如下执行上面的twin_cast规则:

twin_cast(One,Two).

可以通过“;”来进行追问,有时候我们可能不满足于一个答案。

怎么样你是不是已经预见到合一在Prolog中发挥的至关重要的作用了:输出

列表/元组

只要是语言都会有数据结构,因为程序 = 算法 + 数据结构。

Prolog中有两个非常重要的数据结构:列表和元祖。列表是变长的容器:像[1,2,3]这样表示,元组是定长的容器,像(1,2,3)这样表示。两个数据结构非常简单,但是和合一配合起来的时候会十分强大。

| ?- (,,) = (,,).

yes

 | ?- [A,B,C] = [A,B,C].

yes

如果两个元组拥有的元素数量相同并且每个元素可以合一 ,则它们整体就是合一的。

加入变量会更有趣:

| ?- [A,B,C] = [,,].

A =
B =
C = yes

并且变量在哪一侧无所谓,只要Prolog认为它们可以相同,那么就可以合一:

| ?- [A,2,C] = [1,B,3].

A = 1
B = 2
C = 3 (16 ms) yes

这让我想到小时候玩的一种扑克牌游戏了,当抓到大王或小王的时候,我可以把它看做是任何一张牌。

另外列表拥有一个元组不拥有的功能,这个功能在后面介绍的递归中会被广泛使用。 那就是通过[Head|Tail]解析列表,很简单看个例子就明白了:

| ?- [Head|Tail] = [,,,].

Head =
Tail = [,,] yes

Head绑定到1,Tail绑定到剩下的元素,Tail仍然是一个列表。因为Prolog的变量是没有数据类型之分的,所以它可以很容易的绑定为列表或元组,这点有点动态语言的性质,Prolog中也有匿名变量:

| ?- [a,b,c,d,e]=[_,_|[Head|_]].

Head = c

yes

这样我们就能指定提取列表中某一个元素了。

递归

我们趁热打铁看看Prolog中递归是怎么发挥作用的,留心它和命令式语言中的不同

我们就以经典的斐波那契数列做例子吧,我们先来看下命令式语言是如何实现,这个再熟悉不过了:

static void Main(string[] args)
{
Console.WriteLine(Fibonacci()); Console.ReadKey();
}
static int Fibonacci(int n)
{
if (n == ) return ;
if (n == ) return ;
return Fibonacci(n - ) + Fibonacci(n - );
}

在看Prolog是如何实现之前,我们先来描述一下关于斐波那契数列的既定事实和规则,因为Prolog正是基于事实和规则的一门语言:

  • 第一个数是0;
  • 第二个数是1;
  • 从第三个数开始等它前面两个数之和。

好了和上面对应的Prolog的代码也是三行:

fibonacci(,).
fibonacci(,).
fibonacci(N,V) :- N > , N1 is N -, N2 is N -, fibonacci(N1,V1),fibonacci(N2,V2), V is V1 + V2.

:is是Prolog中内置的一个谓词。

比较起来你可能觉得和C#代码差不多,都很简洁,Prolog有什么特别的或者说优势呢?其中区别各位自己体会吧,我也在慢慢体会,这个区别就是声明式语言命令式语言之间的区别。

这个例子太简单不能很好体现Prolog的优势,下一篇文章我们看下用Prolog是如何解决数独和八皇后问题的。我们来看下《七周七语言》这本书中几个递归的例子,也许你能感兴趣不妨试试:

count(,[]).
count(Count,[Head|Tail]):- count(TailCount,Tail),Count is TailCount + . sum(,[]).
sum(Total,[Head|Tail]):- sum(Sum,Tail),Total is Sum + Head. average(Average,List):- sum(Sum,List),count(Count,List),Average is Sum/Count.

count是求列表元素的个数,sum是求和,average是求平均值。

内置谓词

所谓内置的谓词,可以简单理解为Prolog提供的一些基本“功能”,就像.net中的一些类库一样。上面提到的is就是。

length:获取列表的长度:

| ?- length([,,],L).

L = 

yes

append:可以用来合并两个列表,当然还有很多其他功能:

| ?- append([],[],What).

What = [,]

yes

用于列表的减法:

| ?- append([],What,[,,]).

What = [,]

yes

排列组合:

| ?- append(One,Two,[,,,]).

One = []
Two = [,,,] ? ; One = []
Two = [,,] ? ; One = [,]
Two = [,] ? ; One = [,,]
Two = [] ? ; One = [,,,]
Two = [] ( ms) yes

fd_domain:验证值是否在一个范围之内:

| ?- fd_domain(,,).

yes

| ?- fd_domain([,,,],,).

yes

| ?- fd_domain([,,,],,).

no

fd_all_different:检查列表中是否有重复元素:

| ?- fd_all_different([,,]).

yes
| ?- fd_all_different([,,]). no

member:检查某一个值是否在一个列表内:

| ?- member(,[,]).

true ? 

yes
| ?- member(,[,]). no

好了关于Prolog的基本概念就介绍到这,下一篇文章我们会看下通过这些基本概念Prolog是如何解决一些复杂问题的。想了解更多推荐大家去看看这本书。

Prolog学习:基本概念的更多相关文章

  1. Prolog学习:基本概念 and Asp.net与Dojo交互:仪器仪表实现

    Asp.net与Dojo交互:仪器仪表实现 项目中需要用到仪器仪表的界面来显示实时的采集信息值,于是便遍地寻找,参考了fusionchart和anychart之后,发现都是收费的,破解的又没有这些功能 ...

  2. 分布式强化学习基础概念(Distributional RL )

    分布式强化学习基础概念(Distributional RL) from: https://mtomassoli.github.io/2017/12/08/distributional_rl/ 1. Q ...

  3. C#学习基础概念二十五问

    C#学习基础概念二十五问 1.静态变量和非静态变量的区别?2.const 和 static readonly 区别?3.extern 是什么意思?4.abstract 是什么意思?5.internal ...

  4. js面向对象学习 - 对象概念及创建对象

    原文地址:js面向对象学习笔记 一.对象概念 对象是什么?对象是“无序属性的集合,其属性可以包括基本值,对象或者函数”.也就是一组名值对的无序集合. 对象的特性(不可直接访问),也就是属性包含两种,数 ...

  5. 通过Redux源码学习基础概念一:简单例子入门

    最近公司有个项目使用react+redux来做前端部分的实现,正好有机会学习一下redux,也和小伙伴们分享一下学习的经验. 首先声明一下,这篇文章讲的是Redux的基本概念和实现,不包括react- ...

  6. SQL Server数据库学习笔记-概念数据模型

    概念数据模型(Conceptual Data Model)也称为信息模型.它是对客观事物及其联系的抽象,用于信息世界的建模,是现实世界到信息世界的第一层抽象,是数据库设计人员进行数据库设计的有力工具. ...

  7. Ext学习-基础概念,核心思想介绍

    1.目标   本阶段的目标是通过学习一些基础知识来对EXTJS有个整体的了解,知道EXTJS的基础语法,核心设计思想等等 2.内容   1.基础部分学习   2.EXTJS类系统介绍   3.EXTJ ...

  8. WebRTC 学习之 概念总结

    在学习WebRTC的时候,接触到了好多新的概念,在这里做一下备忘吧 RTMP协议 Real Time Messaging Protocol(实时消息传输协议).该协议基于TCP,是一个协议族,包括RT ...

  9. Prolog学习:数独和八皇后问题

    上一篇简单介绍了下Prolog的一些基本概念,今天我们来利用这些基本概念解决两个问题:数独和八皇后问题. 数独 数独是一个很经典的游戏: 玩家需要根据n×n盘面上的已知数字,推理出所有剩余空格的数字, ...

随机推荐

  1. python(38):sys.argv,sys.argv.pop(),获取用户的外部输入,非指定

    见下面的例子(一): # /usr/bin/env python # coding=utf8 import os import requests import sys if __name__ == & ...

  2. mac book air 与 virtual box 网络互访 安装centos7 mini

    Host-only Adapter     主机模式     虚拟机之间可以访问...主机可以访问虚拟机 NAT                          网络地址转换模式(Network A ...

  3. 【Linux技术】常用的Linux系统调用

    下面一些函数已经过时,被新的更好的函数所代替了(gcc在链接这些函数时会发出警告),但因为兼容的原因还保留着,这些函数将在前面标上“*”号以示区别. 一.进程控制 fork 创建一个新进程 clone ...

  4. Ubuntu首次安装后root权限解锁

    在ubuntu系统下,为了安全起见,在安装过程中,系统屏蔽了用户设置root用户.导致很多用户在使用过程中不知道root密码到底是什么. 可以使用如下方法解决: 先解除root锁定,为root用户设置 ...

  5. django创建应用

    创建应用--在一个项目中可以创建多个应用,每个应用进行一种业务处理 打开CMD,进入project(目录名)的目录下,输入命令创建名为myApp的app: python manage.py start ...

  6. java中ThreadExecutor使用注意

    如果使用了submit(Runnable task) 就会出现这种情况,任何的错误信息都出现不了! 这是因为使用submit(Runnable task) 的时候,错误的堆栈信息跑出来的时候会被内部捕 ...

  7. iOS 检测网络状态 自动判断 认为提示网络改变

    检测网络状态 在网络应用中,需要对用户设备的网络状态进行实时监控,目的是让用户了解自己的网络状态,防止一些误会(比如怪应用无能)根据用户的网络状态进行智能处理,节省用户流量,提高用户体验WIFI\3G ...

  8. Beef安装与简单使用

    安装 Debian / Ubuntu 安装依赖 sudo apt-get update sudo apt-get install curl git curl -sSL https://raw.gith ...

  9. Mongodb 的常用方法,在可视化工具执行

    查询: db.getCollection('message').find({"userId":"31257"}) 查询总数: db.getCollection( ...

  10. php的变量引用与销毁机制

    在php中,符号"&"表示引用. 1.看看不引用的情况是这样子: $a  = "hello world";//定义一个变量,下面赋值给$b $b = $ ...