我正在Prolog中开发一个任务调度程序。首先让我向您展示我的代码的简化版本。它是这样的:
handle_activable(As) :-
reset_flags,
findall(A,catch(activable(A),Exception,flag(marked_activable,A)),As),
activate_all(As).
activable/1
有两个版本,但最相关的版本是(再次简化):
activable(T) :-
task(T), /* T is a task */
inactive(T), /* The task is currently inactive */
(\+checked(T) ->
mark_checked(T),
!,
/*
Here would go the set of conditions
and statements to determine if task T
is activable or not. They may internally
call activable/1.
*/
asserta(flag(marked_activable,T))
;
/*
This task was already checked and the
result is stored in flag(marked_activable,T)
fact.
*/
throw(exception(already_checked,T))
).
问题是,在“条件设置检查”中,activable/1
可能被间接调用。这就是我需要使用checked/1
的原因,以避免不必要的循环。
我猜测我使用findall/3
的方式还可以,但由于As
始终被实例化为空列表[]
,我开始认为它有问题。
我想问你的第一件事是catch(...)电话。这是对的吗?我的意思是,如果在activable/1
调用期间,程序抛出异常,因为任务已经被检查过,A
是否仍然会被实例化(以便我可以在flag(marked_activable,A)
中使用它)?如果没有,你知道任何解决方法吗?
我想问你的第二件事是关于算法的正确性。我已经在这方面工作了很长时间,我尽力拥有一个高效,强大和可靠的代码。真正的困难在于条件集检查,其中任务的关系起着重要的作用并产生复杂的约束。你认为“找到可激活的任务”的方式是好的吗?
答案 0 :(得分:0)
使用内置的catch/3
谓词,传递信息的正确方法是Catcher
一词。
catch(:Goal, +Catcher, :Recover)
根据SWI-Prolog文档,Goal
是Catcher
与throw/1
的参数统一的最内层目标,Goal
生成的所有选择点被剪切,系统回溯到catch/3
的开头,同时保留抛出的异常术语。
因此,有一个规则:
generate(info1).
generate(info2).
generate(info3).
generate(info4).
rule(D) :-
generate(D),
...
throw(error_info(D)).
捕获此规则的结果将是这样的:
?- catch(rule(D), Exception, write(Exception)).
error_info(info1).
Exception = error_info(info1).
?- catch(rule(_), error_info(E), write(E)).
info1.
E = info1.