2

我目前正在尝试弄清楚如何在 swi-prolog 中跨模块使用相同的运算符及其相关谓词。

我有一个“主”文件(ch20.pl),我通过键入以下内容从 swi-prolog 交互式加载:

[ch20].

ch20.pl当前包含:

:- use_module(ch20_examples).
:- use_module(ch20_Ires).

ch20_examples.pl:

:- module(ch20_examples, [example/2, attribute/2]).

attribute(size, [small, large]).
attribute(shape, [long, compact, other]).
attribute(holes, [none, 1, 2, 3, many]).

example(nut, [size=small, shape=compact, holes=1]).
example(screw, [size=small, shape=long, holes=none]).
example(key, [size=small, shape=long, holes=1]).
example(nut, [size=small, shape=compact, holes=1]).
example(key, [size=large, shape=long, holes=1]).
example(screw, [size=small, shape=compact, holes=none]).
example(nut, [size=small, shape=compact, holes=1]).
example(pen, [size=large, shape=long, holes=none]).
example(scissors, [size=large, shape=long, holes=2]).
example(pen, [size=large, shape=long, holes=none]).
example(scissors, [size=large, shape=other, holes=2]).
example(key, [size=small, shape=other, holes=2]).

ch20_Ires.pl:

:- module(ch20_Ires,
            [   op(900, xfy, <-),
                (<-)/2
            ]).
:- use_module(ch20_utils).

R <- residual_info(Attribute) :-
    findall(X, (example(_, Attributes), member(Attribute=X, Attributes)), Values),
    list_to_set(Values, Values_set),
    setof(Class, Class^Attr^example(Class,Attr), Classes_set),
    Values_prob_sum <- sum_list(Values_set, value_prob(Values, Classes_set, Attribute)),
    R <- -Values_prob_sum, !.

R <- value_prob(Values, Classes_set, Attr, Val) :-
    include(==(Val), Values, Value_count_list),
    Value_count_n <- len(Value_count_list),
    Values_n <- len(Values),
    Val_prob <- Value_count_n / Values_n, 
    R <- Val_prob * sum_list(Classes_set, cond_prob(Attr, Val)), !.

R <- cond_prob(Attr, Val, Class) :-
    findall(_, (example(Class, Class_FeatureList), member(Attr=Val, Class_FeatureList)) , Class_list),
    Class_n <- len(Class_list),
    findall(_, (example(_, FeatureList), member(Attr=Val, FeatureList)), Feature_count_list),
    Feature_count <- len(Feature_count_list),
    (Class_n > 0, Cond_prob <- Class_n / Feature_count, R <- Cond_prob * log2(Cond_prob)
    ;
    R <- 0), !.

ch20_utils.pl:

:- module(ch20_utils,
            [   op(900, xfy, <-),
                (<-)/2
            ]).

R <- log2(X) :- R <- log(X) / log(2), !.
R <- len(L) :- length(L, R), !.
Sum <- sum_list([], _) :- Sum <- 0.
Sum <- sum_list([H|T], Func) :- 
    New_sum <- sum_list(T, Func), 
    !, Func =..Func_list, 
    append(Func_list,[H],Apply_func_list),
    Apply_func =..Apply_func_list,
    Sum <- New_sum + Apply_func.

R <- X :- compound(X), X =..[OP,X2,X3], R2 <- X2, R3 <- X3, Expr =..[OP,R2,R3], R is Expr, !.
R <- X :- R is X, !.

我目前的目标是能够评估:

?- X <- residual_info(size).

但它只是用上面的设置返回 false ......

请注意,我使用 <- 运算符是为了使代码更具可读性,并能够评估以下化合物:

X <- 18*log2(19)-5.

但这也意味着我的代码非常依赖于部分:

R <- X :- compound(X), X =..[OP,X2,X3], R2 <- X2, R3 <- X3, Expr =..[OP,R2,R3], R is Expr, !.
R <- X :- R is X, !.

我试过搞乱多文件谓词,但我认为我不明白如何使用它。

但是,如果 ch20_Ires.pl 文件更改为:

:- module(ch20_Ires,
            [   op(900, xfy, <-),
                (<-)/2
            ]).
 R <- log2(X) :- R <- log(X) / log(2), !.
 R <- len(L) :- length(L, R), !.
 Sum <- sum_list([], _) :- Sum <- 0.
 Sum <- sum_list([H|T], Func) :- 
     New_sum <- sum_list(T, Func), 
     !, Func =..Func_list, 
     append(Func_list,[H],Apply_func_list), 
     Apply_func =..Apply_func_list, 
     Sum <- New_sum + Apply_func.

R <- residual_info(Attribute) :-
    findall(X, (example(_, Attributes), member(Attribute=X, Attributes)), Values),
    list_to_set(Values, Values_set),
    setof(Class, Class^Attr^example(Class,Attr), Classes_set),
    Values_prob_sum <- sum_list(Values_set, value_prob(Values, Classes_set, Attribute)),
    R <- -Values_prob_sum, !.

R <- value_prob(Values, Classes_set, Attr, Val) :-
    include(==(Val), Values, Value_count_list),
    Value_count_n <- len(Value_count_list),
    Values_n <- len(Values),
    Val_prob <- Value_count_n / Values_n,
    R <- Val_prob * sum_list(Classes_set, cond_prob(Attr, Val)), !.

R <- cond_prob(Attr, Val, Class) :-
    findall(_, (example(Class, Class_FeatureList), member(Attr=Val, Class_FeatureList)) , Class_list),
    Class_n <- len(Class_list),
    findall(_, (example(_, FeatureList), member(Attr=Val, FeatureList)), Feature_count_list),
    Feature_count <- len(Feature_count_list),
    (Class_n > 0, Cond_prob <- Class_n / Feature_count, R <- Cond_prob * log2(Cond_prob)
    ;
    R <- 0), !.

R <- X :- compound(X), X =..[OP,X2,X3], R2 <- X2, R3 <- X3, Expr =..[OP,R2,R3], R is Expr, !.
R <- X :- R is X, !.

一切正常,我可以执行我的目标:

?- X <- residual_info(size).
X = 1.5421864522230475.

但我真的想将我的逻辑分成更多模块,而不是将所有内容都放在一个文件中。而且我希望能够使用模块应该提供的这个类似公共/私有的系统。

有什么我可以在代码中重新排列的东西,或者我可以用这个多文件谓词以某种方式解决我的问题吗?

顺便说一句,是否有任何书籍教授诸如使用模块和其他高级 prolog 技术之类的内容?因为我发现很难使用 swi-prolog 文档,而且很难用 google 找到示例。

4

1 回答 1

3

模块是 Prolog 标准化中最具争议的问题之一。然后很难找到有关该主题和示例的连贯信息。

恕我直言,您的问题源于对结构的过多期望,它做了一些简单的事情,但产生了复杂的后果,因为它改变了语言元素的一个基本属性:原子,当用作谓词标识符时,变成对 Module:Name,其中 Module 是称为上下文(嗯,有点......我希望有人能用更精确的措辞和参考资料来帮助理解这个重要的话题)。


为了简化您的问题,让我们将 (<-)/2 重命名为 eval/2。然后

:- module(ch20_Ires, []).
:- reexport([ch20_utils, ch20_examples]).

ch20_utils:eval(R, residual_info(Attribute)) :-
    findall(X, (example(_, Attributes), member(Attribute=X, Attributes)), Values),
    list_to_set(Values, Values_set),
    setof(Class, Class^Attr^example(Class,Attr), Classes_set),
    eval(Values_prob_sum, sum_list(Values_set, value_prob(Values, Classes_set, Attribute))),
    eval(R, -Values_prob_sum), !.
...    
% note: moved here from ch20_utils
ch20_utils:eval(R, X) :- R is X, !.

:- module(ch20_utils, [ eval/2 ]).
:- multifile eval/2.

eval(R, log2(X)) :- eval(R, log(X) / log(2)), !.
...

我们从顶线得到预期的结果

17 ?- eval(X, residual_info(size)).
X = 1.5421864522230475.

注意 ch20_utils 中的声明(第一次看到 eval 的地方):

:- multifile eval/2.

这允许在其他模块中继续定义,需要使用 ch20_utils 标识符来限定进一步的定义。然后递归调用将有机会找到这些定义。

注意我将最后一个子句从 ch20_utils 移到了 ch20_Ires。这是必需的,因为该子句是“笼统”规则,因此禁止检查 ch20_Ires 子句:实际上,我得到了

12 ?- eval(X, residual_info(size)).
ERROR: is/2: Arithmetic: `size/0' is not a function

在移动子句之前...


现在,回到原来的问题,你知道操作符只是语法糖:

:- module(ch20_Ires, []).
:- reexport([ch20_utils, ch20_examples]).

ch20_utils:(R <- residual_info(Attribute)) :-
    findall(X, (example(_, Attributes), member(Attribute=X, Attributes)), Values),
    list_to_set(Values, Values_set),
    setof(Class, Class^Attr^example(Class,Attr), Classes_set),
    Values_prob_sum <- sum_list(Values_set, value_prob(Values, Classes_set, Attribute)),
    R <- -Values_prob_sum, !.

...

% note: moved here from ch20_utils
ch20_utils:(R <- X) :- R is X, !.

:- module(ch20_utils,
            [ op(900, xfy, <-),
                (<-)/2
        ]).

:- multifile (<-)/2.

R <- log2(X) :- R <- log(X) / log(2), !.
R <- len(L) :- length(L, R), !.
Sum <- sum_list([], _) :- Sum <- 0.
Sum <- sum_list([H|T], Func) :-
    New_sum <- sum_list(T, Func),
    !, Func =..Func_list,
    append(Func_list,[H],Apply_func_list),
    Apply_func =..Apply_func_list,
    Sum <- New_sum + Apply_func.

R <- X :- compound(X), X =..[OP,X2,X3], R2 <- X2, R3 <- X3, Expr =.. [OP,R2,R3], R is Expr, !.

% R <- X :- R is X, !.

似乎解决了语法问题:

20 ?- X <- residual_info(size).
X = 1.5421864522230475.
于 2013-09-03T08:30:54.753 回答