让我们使用以下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
文件或辅助文件中)并运行它们,显示其结果会更好
答案 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)
(可能更干净)