CLIPS在专家系统开发的应用十分广泛,基于C语言开发的CLIPS很容易嵌入到各种开发环境中,当然也包括C++。然而,CLIPS包含了一个关键字“slots”,这就与qt的关键字“slots”发生了冲突,所以,直接利用网上流传的各种编译好的CLIPS.dll都没办法将CLIPS与Qt结合起来,于是我想到了一个直接暴力的方法——将CLIPS源码中所有单独出现的“slots”改成别的字符(如:Qslots、Cslots等与源码中slots不一样的字符)就可以了,这样一来,不管CLIPS的开发者想要利用原本的“slots”来做什么,我们都可以利用我们重新定义的字符来代替。这样就解决了很多朋友在利用Qt编译CLIPS时候遇到的一大困难,在这里就不展开讲述了。
本文需要解决的问题是,如何将CLIPS中产生的Fact输出到我们想要的任何一个地方?
tips:不想看我推导过程的朋友,可以直接跳转文末看总结。
首先,CLIPS本身提供了一个printout()函数来打印专家系统的slot value,我们先来看看这个函数的形式。
(printout t "待打印的内容" crlf)
待打印的内容输出位置由参数t来给出,通常就是输出到内存窗口里面,如下图所示:
那么除此之外,我们还有别的函数可以打印CLIPS中的Fact吗?当然是有的,基于C语言开发的CLIPS,在源码中多次出现fprintf()函数。我们还有EnvPrintRouter()函数可以做到,根据CLIPS文档的高级版,我们可以查看一些这个函数的基本情况。
int EnvPrintRouter(environment,logicalName,str)
void *environment;
const char *logicalName;
const char *str;
这个函数的基本功能就是把environment中的str打印到logicalName,嗯,,,好像和printout的输出没什么区别。
不过不用担心,我们还有例子呢。。。这个例子的功能很简单,是CLIPS开发者Gary Rirley在帮助一个外国小伙伴关于CLIPS判断语句时给出的对比结果,在这里用到EnvPrintRouter()函数,正好被我看到了,这就直接帖上他的代码过来,在这个例子中,我们可以看到Gary Rirley用到了一下两句话来实现了两次打印,相信有的朋友已经发现了猫腻,一是这个函数给的logicalName是STDOUT (源码定义的stdout),二是这个函数直接将第三个参数打印出来了。注意第一次打印的时候,内容是DOToString(theValue)。结合之前的EnvGetFactSlot()函数,我们可以得知,CLIPS将Fact存入了开头定义的
DATA_OBJECT theValue变量中。
因此,我们只需要将theValue转换成我们C++的常规数据类型就可以进行输出调用了。
以下代码的出处为 http://qaru.site/questions/13797825/clips-getting-facts-of-a-specific-template-from-fact-list
int main()
{
void *theEnv;
void *theFact;
void *templatePtr;
DATA_OBJECT theValue;
theEnv = CreateEnvironment();
EnvBuild(theEnv,"(deftemplate Student (slot Name))");
EnvBuild(theEnv,"(deftemplate Teacher (slot Name))");
EnvAssertString(theEnv,"(Student (Name \"John Brown\"))");
EnvAssertString(theEnv,"(Teacher (Name \"Susan Smith\"))");
EnvAssertString(theEnv,"(Student (Name \"Sally Green\"))");
EnvAssertString(theEnv,"(Teacher (Name \"Jack Jones\"))");
templatePtr = EnvFindDeftemplate(theEnv,"Student");
for (theFact = EnvGetNextFact(theEnv,NULL);
theFact != NULL;
theFact = EnvGetNextFact(theEnv,theFact))
{
if (EnvFactDeftemplate(theEnv,theFact) != templatePtr) continue;
EnvGetFactSlot(theEnv,theFact,"Name",&theValue);
EnvPrintRouter(theEnv,STDOUT,DOToString(theValue));
EnvPrintRouter(theEnv,STDOUT,"\n");
}
EnvPrintRouter(theEnv,STDOUT,"-------------\n");
for (theFact = EnvGetNextFactInTemplate(theEnv,templatePtr,NULL);
theFact != NULL;
theFact = EnvGetNextFactInTemplate(theEnv,templatePtr,theFact))
{
EnvGetFactSlot(theEnv,theFact,"Name",&theValue);
EnvPrintRouter(theEnv,STDOUT,DOToString(theValue));
EnvPrintRouter(theEnv,STDOUT,"\n");
}
}
总结:CLIPS将Fact存入了 DATA_OBJECT 中,我们想要获取CLIPS产生的Fact,只需要从DATA_OBJECT theValue里面取就可以了。至于则么取的问题,请看接下来这行代码:
QString my = DOToString(theValue);
是不是很通俗易懂?