Prolog - 输入和输出


在本章中,我们将看到一些通过 prolog 处理输入和输出的技术。我们将使用一些内置谓词来完成这些任务,并查看文件处理技术。

将详细讨论以下主题 -

  • 处理输入和输出

  • 使用 Prolog 处理文件

  • 使用一些外部文件来读取行和术语

  • 输入和输出的字符操作

  • 构造和分解Atomics

  • 查阅 prolog 文件以了解其他 prolog 程序技术。

处理输入和输出

到目前为止,我们已经看到我们可以编写一个程序并在控制台上执行查询。在某些情况下,我们会在控制台上打印一些用 prolog 代码编写的内容。因此,在这里我们将使用 prolog 更详细地了解写入和读取任务。这就是输入和输出处理技术。

write() 谓词

要写入输出,我们可以使用write()谓词。该谓词将参数作为输入,默认将内容写入控制台。write() 也可以写入文件。让我们看一些 write() 函数的示例。

程序

| ?- write(56).
56

yes
| ?- write('hello').
hello

yes
| ?- write('hello'),nl,write('world').
hello
world

yes
| ?- write("ABCDE")
.
[65,66,67,68,69]

yes

从上面的例子中,我们可以看到 write() 谓词可以将内容写入控制台。我们可以使用“nl”来创建一个新行。从这个例子中可以清楚地看出,如果我们想在控制台上打印一些字符串,我们必须使用单引号('string')。但如果我们使用双引号(“字符串”),那么它将返回一个 ASCII 值列表。

read() 谓词

read() 谓词用于从控制台读取。用户可以在控制台中编写一些内容,该内容可以作为输入并进行处理。read() 通常用于从控制台读取,但也可以用于从文件读取。现在让我们看一个例子来了解 read() 是如何工作的。

程序

cube :-
   write('Write a number: '),
   read(Number),
   process(Number).
process(stop) :- !.
process(Number) :-
   C is Number * Number * Number,
   write('Cube of '),write(Number),write(': '),write(C),nl, cube.

输出

| ?- [read_write].
compiling D:/TP Prolog/Sample_Codes/read_write.pl for byte code...
D:/TP Prolog/Sample_Codes/read_write.pl compiled, 9 lines read - 1226 bytes written, 12 ms

(15 ms) yes
| ?- cube.
Write a number: 2.
Cube of 2: 8
Write a number: 10.
Cube of 10: 1000
Write a number: 12.
Cube of 12: 1728
Write a number: 8.
Cube of 8: 512
Write a number: stop
.

(31 ms) yes
| ?-

tab() 谓词

tab() 是一个附加谓词,可用于在我们编写内容时放置一些空格。因此它接受一个数字作为参数,并打印那么多的空格。

程序

| ?- write('hello'),tab(15),write('world').
hello          world

yes
| ?- write('We'),tab(5),write('will'),tab(5),write('use'),tab(5),write('tabs').
We    will  use   tabs

yes
| ?-

读/写文件

在本节中,我们将了解如何使用文件读取和写入文件。有一些内置谓词可用于从文件读取和写入文件。

告诉和告诉

如果我们想写入除控制台之外的文件,我们可以编写tell()谓词。该tell()谓词将文件名作为参数。如果该文件不存在,则创建一个新文件并写入其中。该文件将被打开,直到我们编写告诉命令。我们可以使用tell()打开多个文件。当调用告诉时,所有文件将被关闭。

序言命令

| ?- told('myFile.txt').
uncaught exception: error(existence_error(procedure,told/1),top_level/0)
| ?- told("myFile.txt").
uncaught exception: error(existence_error(procedure,told/1),top_level/0)
| ?- tell('myFile.txt').

yes
| ?- tell('myFile.txt').

yes
| ?- write('Hello World').

yes
| ?- write(' Writing into a file'),tab(5),write('myFile.txt'),nl.

yes
| ?- write("Write some ASCII values").

yes
| ?- told.

yes
| ?-

输出(myFile.txt)

Hello World Writing into a file     myFile.txt
[87,114,105,116,101,32,115,111,109,101,32,65,83,67,73,73,32,118,97,108,117,101,115]

同样,我们也可以从文件中读取。让我们看一些从文件读取的示例。

所见与所见

当我们想要从文件而不是键盘读取时,我们必须更改当前的输入流。所以我们可以使用 see() 谓词。这将以文件名作为输入。当读操作完成后,我们将使用seen命令。

示例文件 (sample_predicate.txt)

likes(lili, cat).
likes(jhon,dog).

输出

| ?- see('sample_predicate.txt'),
read(X),
read(Y),
seen,
read(Z).
the_end.

X = end_of_file
Y = end_of_file
Z = the_end

yes
| ?-

因此,从这个例子中,我们可以看到使用 see() 谓词我们可以从文件中读取。现在使用seen命令后,控制权再次转移到控制台。所以最后它从控制台获取输入。

处理条款文件

我们已经了解了如何读取文件的特定内容(几行)。现在,如果我们想要读取/处理文件的所有内容,我们需要编写一个子句来处理文件(process_file),直到到达文件末尾。

程序

process_file :-
   read(Line),
   Line \== end_of_file, % when Line is not not end of file, call process.
   process(Line).
process_file :- !. % use cut to stop backtracking

process(Line):- %this will print the line into the console
   write(Line),nl,
   process_file.

示例文件 (sample_predicate.txt)

likes(lili, cat).
likes(jhon,dog).
domestic(dog).
domestic(cat).

输出

| ?- [process_file].
compiling D:/TP Prolog/Sample_Codes/process_file.pl for byte code...
D:/TP Prolog/Sample_Codes/process_file.pl compiled, 9 lines read - 774 bytes written, 23 ms

yes
| ?- see('sample_predicate.txt'), process_file, seen.
likes(lili,cat)
likes(jhon,dog)
domestic(dog)
domestic(cat)

true ?

(15 ms) yes
| ?-

操纵字符

使用 read() 和 write() 我们可以读取或写入Atomics、谓词、字符串等的值。现在在本节中我们将看到如何将单个字符写入当前输出流,或如何从当前输入流读取。因此,有一些预定义的谓词来完成这些任务。

put(C) 和 put_char(C) 谓词

我们可以使用 put(C) 一次将一个字符写入当前输出流。输出流可以是文件或控制台。在其他版本的 Prolog(如 SWI prolog)中,这个 C 可以是字符或 ASCII 代码,但在 GNU prolog 中,它仅支持 ASCII 值。要使用字符而不是 ASCII,我们可以使用 put_char(C)。

程序

| ?- put(97),put(98),put(99),put(100),put(101).
abcde

yes
| ?- put(97),put(66),put(99),put(100),put(101).
aBcde

(15 ms) yes
| ?- put(65),put(66),put(99),put(100),put(101).
ABcde

yes
| ?-put_char('h'),put_char('e'),put_char('l'),put_char('l'),put_char('o').
hello

yes
| ?-

get_char(C) 和 get_code(C) 谓词

要从当前输入流读取单个字符,我们可以使用 get_char(C) 谓词。这将采取角色。如果我们想要 ASCII 代码,我们可以使用 get_code(C)。

程序

| ?- get_char(X).
A.

X = 'A'

yes
uncaught exception: error(syntax_error('user_input:6 (char:689) expression expected'),read_term/3)
| ?- get_code(X).
A.

X = 65

yes
uncaught exception: error(syntax_error('user_input:7 (char:14) expression expected'),read_term/3)
| ?-

构造Atomics

Atomics构造意味着我们可以从一个字符列表中创建一个Atomics,或者从一个 ASCII 值列表中我们也可以创建一个Atomics。为此,我们必须使用atom_chars() 和atom_codes() 谓词。在这两种情况下,第一个参数都是一个变量,第二个参数是一个列表。所以atom_chars()从字符构造Atomics,而atom_codes()从ASCII序列构造Atomics。

例子

| ?- atom_chars(X, ['t','i','g','e','r']).

X = tiger

yes
| ?- atom_chars(A, ['t','o','m']).

A = tom

yes
| ?- atom_codes(X, [97,98,99,100,101]).

X = abcde

yes
| ?- atom_codes(A, [97,98,99]).

A = abc

yes
| ?-

分解Atomics

Atomics分解是指从一个Atomics中,我们可以得到一个字符序列,或者一个ASCII码序列。为此,我们必须使用相同的atom_chars() 和atom_codes() 谓词。但一个区别是,在这两种情况下,第一个参数将是一个Atomics,第二个参数将是一个变量。所以atom_chars()将Atomics分解为字符,而atom_codes()将Atomics分解为ASCII序列。

例子

| ?- atom_chars(tiger,X).

X = [t,i,g,e,r]

yes
| ?- atom_chars(tom,A).

A = [t,o,m]

yes
| ?- atom_codes(tiger,X).

X = [116,105,103,101,114]

yes
| ?- atom_codes(tom,A).

A = [116,111,109]

(16 ms) yes
| ?-

Prolog 中的咨询

咨询是一种技术,用于合并来自不同文件的谓词。我们可以使用 Consult() 谓词,并传递文件名来附加谓词。让我们看一个示例程序来理解这个概念。

假设我们有两个文件,即 prog1.pl 和 prog2.pl。

程序(prog1.pl)

likes(mary,cat).
likes(joy,rabbit).
likes(tim,duck).

程序(prog2.pl)

likes(suman,mouse).
likes(angshu,deer).

输出

| ?- [prog1].
compiling D:/TP Prolog/Sample_Codes/prog1.pl for byte code...
D:/TP Prolog/Sample_Codes/prog1.pl compiled, 2 lines read - 443 bytes written, 23 ms

yes
| ?- likes(joy,rabbit).

yes
| ?- likes(suman,mouse).

no
| ?- consult('prog2.pl').
compiling D:/TP Prolog/Sample_Codes/prog2.pl for byte code...
D:/TP Prolog/Sample_Codes/prog2.pl compiled, 1 lines read - 366 bytes written, 20 ms
warning: D:/TP Prolog/Sample_Codes/prog2.pl:1: redefining procedure likes/2
         D:/TP Prolog/Sample_Codes/prog1.pl:1: previous definition
         
yes
| ?- likes(suman,mouse).

yes
| ?- likes(joy,rabbit).

no
| ?-

现在从这个输出我们可以了解到这并不像看起来那么简单。如果两个文件有完全不同的子句,那么它会正常工作。但是,如果存在相同的谓词,那么当我们尝试查阅该文件时,它将检查第二个文件中的谓词,当它找到某些匹配项时,它只是从本地数据库中删除相同谓词的所有条目,然后加载再次从第二个文件中获取它们。