Prolog:临界区、回溯、错误处理

标签 prolog swi-prolog

我正在尝试在 SWI-Prolog 中编写一个由互斥锁保护的关键部分,并且一直在考虑使用 setup_call_cleanup/3setup_call_catcher_cleanup/4 .

我遇到的问题是我的目标是一系列操作,其中任何一个都可能失败,这意味着系统回溯到setup_call_cleanup 的开始。并调用 Cleanup。不幸的是,通过回溯我无法适本地报告错误。为了说明我的问题,让我们考虑这个简单的例子:

setup_call_cleanup(
      mutex_lock(mtx),
      ( Step1 = true, Step2 = true, Step3 = true ),
      ( mutex_unlock(mtx), writeln([Step1, Step2, Step3]) ).

并将其与以下内容进行比较:

setup_call_cleanup(
      mutex_lock(mtx),
      ( Step1 = true, Step2 = true, fail, Step3 = true ),
      ( mutex_unlock(mtx), writeln([Step1, Step2, Step3]) ).

在第一种情况下一切正常——我可以看到所有步骤都已完成。但在第二种情况下,我看不到 Step1Step2已执行。我想看看它,因为它们可能具有回溯无法撤消的外部副作用。此外,我不想在目标中包含错误处理以使关键部分尽可能精简和快速。

我有两个想法:

  1. nb_setval装饰每一步存储一个值以指示已完成的步骤,
  2. 重新编写步骤代码,以便它们抛出包含问题详细信息的异常。

前者会使代码变得相当臃肿,而后者似乎对我的需求来说过于重量级。有没有类似 setup_nb_call_cleanup 的东西?

最佳答案

我认为,诀窍是一个一个地运行目标,防止错误和失败并返回失败的步骤。一个好的开始是

until_failure((A,B), Result) :-
    !,
    until_failure(A, Result),
    (   var(Result)
    ->  until_failure(B, Result)
    ;   true
    ).
until_failure(G, Result) :-
    (   catch(G, Result, true)
    *-> true
    ;   Result = false(G)
    ).

现在你可以运行,例如,

?- until_failure((Step1 = true,
               Step2 = true, 
               fail,
               Step3 = true), Result),
   writeln([Step1, Step2, Step3]).

[true, true, _5742]
Result = false(fail)

参见 http://swish.swi-prolog.org/p/ReQWsvCg.swinb . SWISH 不允许 处理互斥量,但您可以轻松地将其包装在 with_mutex/2 中。细节主要取决于您希望如何处理非确定性。

关于Prolog:临界区、回溯、错误处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43390782/

相关文章:

csv - 在prolog中将列表元素写入csv

prolog - 如何获取特定知识库的列表?

prolog - 在 Prolog 中将字节列表转换为整数

prolog - Prolog 冒号运算符是什么意思?

database - Prolog 做一个查询

prolog - 定子句语法,如何检查字符串是否为字符?

prolog - 查找与第一个输入元素配对的列表的长度

.net - 如何将类似 Prolog 的推理引擎嵌入到 .NET 应用程序中?

prolog - 理解clpfd中label/5的实现

python - 如何从 swi-prolog 中执行的 python 脚本获取输出值