Prolog:覆盖谓词和使用它之间的区别

2024-03-20

我觉得自己真的很愚蠢,感觉自己错过了一些东西。

我基本上有两个文件:

  • module.pl通用逻辑规则(可重用)
  • state.pl一个针对当前场景

在模块文件中(module.pl)我已经声明:

inside(Food,Eater,T) :-
    isTime(T),
    injestEvent(InjEvent),
    justAfter(T,InjEvent),
    actorOfEvent(InjEvent, Eater),
    objectOfEvent(InjEvent, Food).

Q1)我必须用单例变量(在同一个文件中)声明所有其他谓词,只是为了停止module.pl抱怨它们不存在:

isTime(_T).
justAfter(_Time,_Event).

actorOfEvent(_Event, _ActorOfEvent).
objectOfEvent(_Event,_ActorOfEvent).

是对的吗?

Q2)我不能使用这些谓词justAfter/2我的另一个文件没有说:

user:justAfter/2 的本地定义覆盖模块的弱导入

我怎么能够use我从模块导入的谓词,而不是重新定义它?


Prolog 模块旨在隐藏辅助谓词。它们不提供允许将谓词声明与谓词定义分开的接口概念。这就是为什么如果您导出未定义的谓词,编译器会抱怨的原因。根据您的描述,我假设您尝试过类似的操作:

----- module.pl -----
:- module(module, [
    inside/3, isTime/1, injestEvent/1, justAfter/2, actorOfEvent/2, objectOfEvent/2
]).

inside(Food,Eater,T) :-
    isTime(T),
    injestEvent(InjEvent),
    justAfter(T,InjEvent),
    actorOfEvent(InjEvent, Eater),
    objectOfEvent(InjEvent, Food).
---------------------

结果是:

?- [module].
ERROR: Exported procedure module:justAfter/2 is not defined
ERROR: Exported procedure module:isTime/1 is not defined
ERROR: Exported procedure module:injestEvent/1 is not defined
ERROR: Exported procedure module:objectOfEvent/2 is not defined
ERROR: Exported procedure module:actorOfEvent/2 is not defined
true.

您尝试通过添加本地定义来解决此错误。但这只会导致你描述的第二个问题。当你做类似的事情时:

?- use_module(module).

你导入all导出的谓词module,包括您想要定义的那些state.pl。因此,编译器在加载时会警告您state.pl,该文件正在覆盖这些谓词。例如。和:

----- state.pl -----
isTime(1).
injestEvent(injEvent).
justAfter(1, injEvent).
actorOfEvent(injEvent, eater).
objectOfEvent(injEvent, food).
--------------------

we get:

?- [state].
Warning: /Users/pmoura/Desktop/state.pl:1:
    Local definition of user:isTime/1 overrides weak import from module
Warning: /Users/pmoura/Desktop/state.pl:2:
    Local definition of user:injestEvent/1 overrides weak import from module
Warning: /Users/pmoura/Desktop/state.pl:3:
    Local definition of user:justAfter/2 overrides weak import from module
Warning: /Users/pmoura/Desktop/state.pl:4:
    Local definition of user:actorOfEvent/2 overrides weak import from module
Warning: /Users/pmoura/Desktop/state.pl:5:
    Local definition of user:objectOfEvent/2 overrides weak import from module
true.

虽然这些是warnings而不是错误,调用inside/3谓词will没有给你你想要的:

?- inside(Food,Eater,T).
true.

绑定在哪里?!?让我们跟踪调用以突出显示原因:

?- trace.
true.

[trace]  ?- inside(Food,Eater,T).
   Call: (8) module:inside(_2508, _2510, _2512) ? creep
   Call: (9) module:isTime(_2512) ? creep
   Exit: (9) module:isTime(_2512) ? creep
   Call: (9) module:injestEvent(_2804) ? creep
   Exit: (9) module:injestEvent(_2804) ? creep
   Call: (9) module:justAfter(_2512, _2806) ? creep
   Exit: (9) module:justAfter(_2512, _2806) ? creep
   Call: (9) module:actorOfEvent(_2804, _2510) ? creep
   Exit: (9) module:actorOfEvent(_2804, _2510) ? creep
   Call: (9) module:objectOfEvent(_2804, _2508) ? creep
   Exit: (9) module:objectOfEvent(_2804, _2508) ? creep
   Exit: (8) module:inside(_2508, _2510, _2512) ? creep
true.

跟踪清楚地表明“状态”谓词正在被调用wrong语境。

一个干净的解决方案是使用 Logtalk 对象而不是 Prolog 模块。 Logtalk 扩展了 Prolog 并支持大多数系统,包括 SWI-Prolog。它支持接口/协议作为第一类实体(这解决了您提到的第一个问题),并支持继承和在其使用上下文中调用谓词(这解决了第二个问题)。你可以使用例如

----- common.lgt -----
:- object(common).

:- public([
    inside/3, isTime/1, injestEvent/1, justAfter/2, actorOfEvent/2, objectOfEvent/2
]).

inside(Food,Eater,T) :-
    % call the next predicates in "self", i.e. in the
    % object that received the inside/3 message
    ::isTime(T),
    ::injestEvent(InjEvent),
    ::justAfter(T,InjEvent),
    ::actorOfEvent(InjEvent, Eater),
    ::objectOfEvent(InjEvent, Food).

:- end_object.
----------------------

然后将“状态”表示为:

----- state.lgt -----
:- object(state, extends(common)).

isTime(1).
injestEvent(injEvent).
justAfter(1, injEvent).
actorOfEvent(injEvent, eater).
objectOfEvent(injEvent, food).

:- end_object.
---------------------

快速测试(安装 Logtalk 后):

$ swilgt
...
?- {common, state}.
...
true.

?- state::inside(Food,Eater,T).
Food = food,
Eater = eater,
T = 1.

作为奖励,您可以根据需要定义任意数量的“状态”对象。您还可以拥有默认定义对于“状态”谓词common目的。当“状态”对象不提供特定谓词的定义时,这些将被继承和使用。例如,让我们添加到common该条款:

objectOfEvent(injEvent, drink).

并删除(或注释掉)该条款objectOfEvent(injEvent, food). from state。保存并重新加载并重试查询将为您提供:

?- {*}.   % abbreviation for Logtalk's make
% Redefining object common
...
% Redefining object state
...
true.

?- state::inside(Food,Eater,T).
Food = drink,
Eater = eater,
T = 1.

如果需要,您还可以动态创建新的状态对象,而不是在源文件中定义它们。例如:

?- create_object(s2, [extends(common)], [], [isTime(42), ...]).

This 未必您正在寻找的答案,但这也是最好的答案是使用正确的工具^H^H^H^H 封装机制来完成工作的情况。您的编程模式也是一种非常常见的模式(也是开发 Logtalk 的原因之一)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Prolog:覆盖谓词和使用它之间的区别 的相关文章

  • webpack中动态加载外部模块失败

    我正在尝试建立以下架构 一个核心 React 应用程序 它具有一些基本功能 并且能够在运行时加载其他 React 组件 这些额外的 React 组件可以按需加载 并且它们在构建核心应用程序时不可用 因此它们不能包含在核心应用程序的捆绑包中
  • 如何选择面积最大的对象?

    我用过bwconvhull检测图像的某个部分 正如您在图像中看到的那样 有许多具有特定质心的对象 我想做的是检测面积最大的物体 左起第一个大物体 并忽略其他物体 我应该遵循哪种方法 我将非常感谢您的帮助 以下是代码 由于我仍在努力 所以写得
  • 如何循环遍历对象数组并生成键值对?

    我有一个像这样的对象数组 let someObj items id 12 value true id 34 value true id 56 value false 我想将其添加到现有对象中 其中 id 是该对象的键 如下所示 let ob
  • VBA 架构技巧 - 宏封装

    我拼凑了 Excel 的概念证明 以从数据库获取数据 并需要将其打包 以便可以将其分发给我们的客户 我的第一次尝试只是将所有代码放入代码模块中 但随后在 Excel 中我可以看到宏列表中的所有模块 而我实际上只想要列表中的主要模块 我猜想我
  • Prolog家谱

    我做到了 但没有显示答案 当我询问兄弟姐妹 叔叔 阿姨时 这是我写的 有什么问题吗 uncle X Y male X sibling X Z parent Z Y uncle X Y male X spouse X W sibling W
  • Prolog 中的隔离列表

    我很难理解如何让我的代码显示由偶数和奇数组成的隔离列表 我什至不确定我的理解缺乏什么 显然我对这门语言很陌生 必须在学校使用它 我的命令式和功能性思维不会让我知道这到底是怎么回事 哈哈 现在 不 我不是要求你做我的作业 我只是请你帮我看看我
  • 如何计算嵌套对象的深度?

    我有一个嵌套对象的示例数组 let arr id 0 children id 1 children id 2 children id 3 children id 4 children 我需要计算每个对象的深度级别 在所有对象中我也有一个pa
  • 从 array_map 匿名函数内部调用类方法

    我正在尝试从一个对象中调用我的对象的方法之一array map匿名函数 到目前为止 我收到了预期的错误 致命错误 不在对象上下文中时使用 this 我知道为什么我会收到此错误 我只是不知道如何实现我想要的目标 有人有任何建议吗 这是我当前的
  • 在模块中使用shiny的renderUI

    这是我在 stackoverflow 上的第一个问题 我在闪亮 1 0 5 中遇到模块和 renderUI 的问题 当我在中使用 renderUI 时 Main Part ui lt bootstrapPage uiOutput Dynam
  • 如何在 Perl 中使用变量作为模块名称?

    我知道可以在 Perl 中使用变量作为包变量的变量名 我想使用变量的内容作为模块名称 例如 package Foo our names blah1 blah2 1 在另一个文件中 我希望能够将标量的内容设置为 foo 然后访问中的名称数组F
  • 使用 Gradle 在多个 Android 应用程序之间共享 Android 库

    我有 Android 应用程序 A 和 B 我想将每个应用程序中的重复代码提取到共享库 L 中 如何使用 Gradle 执行此操作 我之前见过这个问题的一些排列 但答案很少 最接近 最好的已问问题是这个 多个 Android 应用程序依赖于
  • 一次性删除不正确的后续解决方案

    我有一个谓词 它找到正确的解决方案 但随后又找到不正确的解决方案 data D data threshold nonredundantbumps D 5 Bs write D 3 6 7 8 2 4 5 6 9 4 7 3 D 3 6 7
  • JAVASCRIPT - 为什么这个对象没有改变?

    function myFunc theObject theObject make Ford model Focus year 2006 var mycar make Honda model Accord year 1998 var x my
  • 将 SWI Prolog 代码编译为 Windows 可执行文件 - 解析器 Grails3 项目

    我正在尝试构建解析器 Grails3 项目https github com RichardMoot Grail https github com RichardMoot Grail谁的教程是http www labri fr perso m
  • node.js 模块/导出系统:是否可以将模块导出为函数

    我想在 Dispatch js 中做这样的事情 function handle msg exports handle 这在调用index js中 var dispatch require Dispatch dispatch data 有任何
  • 如何让 Prolog 解释你的结果超出真实的陈述

    我有以下事实和规则 flight sea msp flight msp jfk route A B flight A B route B A flight A B route A C flight A B flight B C 当查询rou
  • for 循环内的 Promise 的 setTimeout

    我想做的是这样的 循环数据集合 对于每个数据元素调用 API 等待 Promise 失败或解析 暂停 30 秒 然后对下一个数据元素再次执行此操作 直到没有任何内容可以迭代集合 最后显示 完成 消息 到目前为止 这是我编写的代码 在其他问题
  • Django“模型”对象不可迭代

    我有一张表 其中显示了已注册的员工 我想根据他们的数据库生成一个简单的 HTML 页面 其中包括他们的姓名 id 职称等 为此 我将一个 id 传递给视图 以便它可以获取相应用户的详细信息并向我显示 一切正常 直到出现错误对象不可迭代 下面
  • 使用循环将对象添加到列表(python)

    我正在尝试使用 while 循环将对象添加到列表中 基本上这就是我想做的 class x pass choice raw input pick what you want to do while choice 0 if choice 1 E
  • 为什么 TypeScript 混合了模块和原型模式?

    我正在查看此页面上 TypeScript 生成的 JS 代码 http www typescriptlang org Playground http www typescriptlang org Playground 基本上 要创建一个Gr

随机推荐