1

我正在 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))?如果没有,您知道任何解决方法吗?

我想问你的第二件事是关于我的算法的正确性。我已经为此工作了很长时间,并且尽我所能来编写高效、健壮和可靠的代码。真正困难的是在一组条件检查中,其中任务的关系发挥了重要作用并产生了复杂的约束。你觉得“寻找可激活任务”的方式好不好?

4

1 回答 1

0

使用内置catch/3谓词,传递信息的正确方法是通过Catcher术语。

catch(:Goal, +Catcher, :Recover)

根据 SWI-Prolog 文档,是与 的参数相结合Goal的最里面的目标,由 生成的所有选择点都被剪切,系统回溯到起点,同时保留抛出的异常项。因此,具有如下规则:Catcherthrow/1Goal 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.
于 2013-03-25T11:49:52.040 回答