如何在shell调用中使用SWI-Prolog中的几个自由变量显示模式匹配目标的结果?

时间:2012-08-01 12:34:35

标签: shell prolog non-interactive

让我们使用以下prolog基础:

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

sdesciencelover在shell调用中询问swi-prolog中的how to show the results of pattern-matching goals,并得到一个答案,对查询进行手动转换,然后写一个。

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

我试图从管道中提供命令,但它不能很好地工作(我无法检测到它何时完成结果写入,因此它只是挂起,之后没有换行符分隔答案):< / p>

(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 个答案:

答案 0 :(得分:3)

到目前为止,我发现了以下方法:

gprolog

使用false's answer,我发现必须在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.,然后运行查询{{由于我们在文件顶部添加了始终为false的谓词,因此只会在控制台上打印一个无关的a(fail).

no询问要做什么时(即多个结果或单个结果而gprolog无法检测到它是最后一个),这将运行查询gprolog,阅读consult('kb.pl'), actual_query.,要求a打印所有结果,然后它将运行查询gprolog,它只会在控制台上打印一个无关的(fail).,因为它们只是分组括号,因此查询等同于no

xsb

可以使用fail.,其中./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.会告诉它退出。

swi-prolog

我还没有找到解决方案。

[rant]所有这些都会变得如此简单,如果构建prolog实现的人实际上想要非交互式地使用它们,就像大多数其他语言一样。[/ rant]

答案 1 :(得分:2)

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

$ echo a| gprolog --query-goal 'X = 1 ; X =2'
GNU Prolog 1.4.1
By Daniel Diaz
Copyright (C) 1999-2012 Daniel Diaz
| ?- X = 1 ; X =2.

X = 1 ? a

X = 2

yes

答案 2 :(得分:1)

您可能已经找到了解决问题的方法,但无论如何,这是我的方法。您总是可以递归到内置谓词包。您可以阅读文档中的内容,这样您就可以了解更多信息。

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(不确定是否是正确的说明方式,但我希望你得到它)

答案 3 :(得分: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谓词)。 您必须将interface替换为kb(或者您将文件命名为),interface:get_args替换为kb:father(X,Y), saysOhNo(Y) 使用辅助谓词prolog文件,例如run(X,Y):- father(X,Y), saysOhNo(Y)(可能更干净)