3

让我们使用以下序言库:

father(anakinSkywalker, princessLeia).
father(anakinSkywalker, lukeSkywalker).
saysOhNo(lukeSkywalker).

sdesciencelover询问如何通过shell 调用在 swi-prolog 中显示模式匹配目标的结果,并得到了对查询进行手动转换的答案,以进行写入。

swipl -q -s kb.pl -t "father(anakinSkywalker,X), writeln(X), false"

结果:

princessLeia
lukeSkywalker

当一个人只有几个带有一个自由变量的查询时,这很好用,但是手动转换每个查询变得乏味,如果我们想要正确输出每个变量的名称及其结果,很快就会变得非常烦人。例如,要运行查询father(AVariable, Another),需要编写:

swipl -q -s kb.pl -t "father(AVariable,Another), write('AVariable='), write(AVariable), write(', Another='), writeln(Another), false"

结果:

AVariable=anakinSkywalker, Another=princessLeia
AVariable=anakinSkywalker, Another=lukeSkywalker

我试图从管道向它提供命令,但效果不佳(我无法检测到它何时完成写入结果,所以它只是在之后挂起,并且没有换行符分隔答案):

(echo "father(X,Y)."; while true; do echo ";"; done) | swipl -q -s kb.pl

结果 :

X = anakinSkywalker,
Y = princessLeia X = anakinSkywalker,
Y = lukeSkywalker.

swipl hangs here, and needs to be stopped with Control-C.

我知道我可以使用sed脚本来预处理查询,添加必要的代码来打印大写字母的变量,但它需要大量的工作来处理复杂的查询,例如必须满足两个谓词:

father(X,Y), saysOhNo(Y).

为了始终给出正确的结果,需要为 prolog 编写一个解析器,这将是无用的工作,因为 prolog 已经知道如何以交互方式执行此操作。

所以这是我的问题:有没有办法告诉 GNU prolog 或 SWI prolog(或任何其他可以轻松安装在 linux 上的免费版本)运行一些查询并打印结果,就像它们以交互方式进行一样,但不需要我手动输入(或复制粘贴)每个查询?

编辑:一种将一系列查询存储在文件中(在kb.pl文件中或辅助文件中)并全部运行它们的方法,显示它们的结果会更好。

4

4 回答 4

3

到目前为止,这是我找到的方法:

gprolog

使用false 的答案,我发现必须在kb.pl文件顶部添加一行:

a(_) :- fail.

然后使用./query.sh kb.pl "father(X,Y), saysOhNo(Y)",其中query.sh是:

#!/bin/sh
echo "a(fail)." | gprolog --query-goal "consult('$1'), $2"

当查询立即返回时(即没有结果或单个结果并gprolog设法检测到它是最后一个),这将运行查询consult('kb.pl'), actual_query.,然后运行查询a(fail).,这将简单地在控制台上打印一个无关紧要no的内容,这要归功于始终 -我们在文件顶部添加的错误谓词。

gprolog询问要做什么时(即几个结果,或一个结果gprolog但无法检测到它是最后一个),这将运行查询,consult('kb.pl'), actual_query.读取a要求gprolog打印所有结果的查询,然后运行查询(fail).只需在控制台上打印一个无关no的,因为这些只是分组括号,所以查询相当于fail..

xsb

可以使用./query.sh kb.pl "father(X,Y), saysOhNo(Y)",其中query.sh是:

#!/bin/sh
(echo "consult('$1'), ${2%.}."; yes halt.) | xsb --noprompt --quietload --nobanner

xsb询问下一步要做什么时,如果用户键入一个非空字符串,后跟enter,它将打印下一个结果,否则它将停止搜索当前查询的解决方案。因此,使用该yes halt.命令,我们输入了无限的非空行流。xsb将所有结果打印到查询中(每次读取halt.,因为它是一个非空字符串,它将继续下一个结果),并返回到它的提示。然后,halt.它收到的以下内容将告诉它退出。

swi-prolog

我还没有找到解决办法。

[rant]如果构建 prolog 实现的人真的考虑以非交互方式使用它们,所有这一切都会简单得多,就像大多数其他语言一样。[/rant]

于 2012-08-08T09:47:34.470 回答
2

--query-goal您可以在 GNU中使用命令行选项。像这样:

$回声| gprolog --query-goal 'X = 1 ; X =2'
GNU 序言 1.4.1
丹尼尔·迪亚兹
版权所有 (C) 1999-2012 Daniel Diaz
| ?- X = 1 ; X = 2。

X = 1 ? 一种

X = 2

是的
于 2012-08-01T13:48:42.383 回答
1

您可能已经为您的问题找到了解决方案,但无论如何,这是我的方法。您始终可以递归到 bagof 内置谓词。您可以在文档中阅读它的作用,这样您将了解更多有关它的信息。

swipl -q -s starwars.pl -t "bagof(X, Y^father(X,Y), BagOfFathers), bagof(Y, X^father(X,Y), BagOfChildren), writeln(BagOfFathers), writeln(BagOfChildren)."
[anakinSkywalker,anakinSkywalker]
[princessLeia,lukeSkywalker]

您也可以稍后将其作为映射或您想要的任何内容进行处理,关系是 1:1(不确定是否是正确的表述方式,但我希望您能理解)

于 2013-03-07T13:49:31.750 回答
0

您可以将以下 bash 脚本用于 swi-prolog:

#!/bin/sh

exec swipl -q  -f none -g "load_files([interface],[silent(true)])" \
         -t interface:get_args -- $*

这将加载文件interface.pl并调用谓词get_args/0
以获取您可以调用的命令行参数:

current_prolog_flag(argv, Arguments)

当然,您可以更改加载的谓词/文件的名称。
参数抑制信息性消息,silent(true)例如介绍文本

编辑:您收到的错误消息是因为您可能没有interface.pl文件(既不是 get_args/0 谓词)。您将不得不替换interfacekb(或无论如何命名文件),并在您的 prolog 文件中interface:get_args使用kb:father(X,Y), saysOhNo(Y) 使用辅助谓词,例如run(X,Y):- father(X,Y), saysOhNo(Y)(可能更干净)

于 2012-08-01T14:41:01.177 回答