4

我正在使用自定义逻辑库在 Android 中运行嵌入式库 [tuProlog (2p.jar)] Prolog 推理引擎,我可以在 Android ListView 中成功查询和显示(某些)结果。

显示的只是推理引擎本身的结果,而不是像 Prolog 'write' 语句(默认情况下)写入 STDOUT 的辅助命令。

我需要在 Android 变量中捕获“写入”打印到 STDOUT 的结果以显示给用户。总的想法(我没有与 ListView 结婚来实现)是模拟命令行交互,如果他们运行基于 Java 的 Prolog Interpreter 终端界面,则会进行该交互。

为了完成这个项目,我想坚持知识工程领域而不是进入系统工程领域,所以我将不胜感激对这个问题的任何见解。

我的研究将我带到这里作为进一步研究的途径,但是系统的东西很快就超出了我的经验。

非常感谢提前....

4

1 回答 1

4

经过我自己的一些研究和与 tuProlog 开发人员的进一步讨论后,我有一个解决这个问题的方法,我认为值得与这个社区分享......

这个问题的整体背景是让任何Prolog 实现在“正确”的 Android 上工作,作为以后更有趣的应用程序(专家系统、游戏 AI 和自然语言接口)的基础架构。

最大的障碍是Prolog 是一个基于“控制台”的解释性环境,它打印到 STDOUT,虽然 Android 允许控制台打印活动,但默认情况下它将所有这些活动都发送到/dev/null。

因此,有两组问题需要解决(1)是否有任何Prolog 可移植到 Android 环境,以及(2)如何“正确”处理路由到/dev/null时捕获控制台输出的问题。

解决方法(1):我们选择了tuProlog 网站,官方来源可以找到:Google Code Repository - tuProlog。他们将 prolog 设计为嵌入到单个 JAR 文件中,特别适用于 Android。他们是我们发现的唯一一个这样做的人,他们对开发人员“响应”。他们的东西是开源 Java/Android并且他们有一个Android Prolog 应用程序即将推出更新。询问他们的代码对于找到合适的解决方案是非常宝贵的。

寻址(2):为这项研究增加最大价值的链接是:从 PrintStream 读取将 Java OutputStream 转换为 InputStream,最终将最有用的StreamWriter 转换为 OutputStream

具体来说,需要做的是

  • 创建一个ByteArrayOutputStream对象以从打印到控制台 ( System.out ) 的过程中捕获二进制数据。
  • 创建PrintStream对象(使用 ByteArrayOutputStream),在其中设置System.setOut(控制控制台输出 [ System.out.println ] 的位置)
  • 重新路由系统输出
  • 将所需的控制台打印输出捕获到字符串变量
  • 将该字符串(在此 Android 项目的情况下)添加到列表视图的一行
  • 通知 Listview数据已更改
  • 重置ByteArrayOutputStream 对象(以避免串联)

这是代码

   // OutPutStream I/O Experimental Stuff
   PrintStream orgStream   = System.out;

   // ByteArray Sub Experimental Stuff
   ByteArrayOutputStream baos = new ByteArrayOutputStream();
   PrintStream psout = new PrintStream(baos, Boolean.TRUE); // Using autoFlush


   // Instantiate an instance of the Prolog Engine. 
   //Do this only once because it's VERY expensive.
   Prolog engine;


    // ReRouting Print Streams 
    // (Inside method we need to capture console output)
    System.setOut(orgStream);           // Set the System Output Stream  


    String myResult = baos.toString();      // returns the actual text 
    myChatListItems.add(myResult);          // Add Text to New ListView Row  
    chatBotAdapter.notifyDataSetChanged();  // notify the Adapter to Refresh
    baos.reset();                           // Reset the ByteArrayOutputStream

      System.setOut(orgStream);  // RESET the System Output Stream 

最后说明:tuProlog 考虑了控制台打印问题并围绕它设计了这个特定的实现,使用侦听器和事件的组合来正确解决 Prolog“写入”命令的捕获以及其他问题。

通过仔细阅读用户指南中建立的首选方法,可以很容易地解决严格的 Prolog 查询……开发人员可以从中快速找到他们需要的东西。

这是对 Prolog 引擎功能的捕获,例如WriteSpyError事件,这些功能更难以确定(我最终咨询了开发人员)。为此,您需要询问他们的CUIConsole的 Android 实现(与他们的CUIConsole的控制台实现相反,后者“不同”)。

简而言之,答案是:(a) 建立一个 Listener,然后(b) 为事件的发生做准备

这是代码:

    // Establish Prolog engine and it's appropriate listeners
    // [Warning, Output, and Spy] 
    engine = new Prolog();
    engine.addWarningListener(this);
    engine.addOutputListener(this);
    engine.addSpyListener(this); 

//// PROLOG CONSOLE OUTPUT MECHANISMS *******************************

@Override
public void onSpy(SpyEvent e) {
    Log.d(TAG, "** LG'd onSpy => SpyEvent Occured ** " );
    System.out.println("** onSpy => SpyEvent Occured ** \n ");
    myChatListItems.add( e.getMsg() );
    chatBotAdapter.notifyDataSetChanged();

}


@Override
public void onOutput(OutputEvent e) {
    Log.d(TAG, "** LG'd: onOutput => OutputEvent Occured ** " );
    System.out.println("** onOutput => OutputEvent Occured ** \n ");
    myChatListItems.add( e.getMsg() );
    chatBotAdapter.notifyDataSetChanged();

}


@Override
public void onWarning(WarningEvent e) {
    Log.d(TAG, "** LG'd: onWarning => WarningEvent Occured ** " );
    System.out.println("** onWarning => WarningEvent Occured ** \n ");
    myChatListItems.add( e.getMsg() );
    chatBotAdapter.notifyDataSetChanged();

}

结束说明: 对于那些对 “Android 上的 Prolog”感兴趣的人,我很乐意提供我编写的任何代码或我拥有的资源,以便在此过程中为您提供帮助。请不要犹豫,问。

于 2012-01-18T12:26:12.920 回答