I am currently trying to figure out how to use the same operator and its related predicates across modules in swi-prolog.
I have a 'main' file (ch20.pl) which I load from the swi-prolog interactive by typing:
[ch20].
ch20.pl currently contains:
:- 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, !.
My current goal is to be able to evaluate:
?- X <- residual_info(size).
but it just returns false with the setup above...
Note that I am using the <- operator in an attempt to make the code a little more readable, and to be able to evaluate compounds like:
X <- 18*log2(19)-5.
But this also means that my code is very depended on the part:
R <- X :- compound(X), X =..[OP,X2,X3], R2 <- X2, R3 <- X3, Expr =..[OP,R2,R3], R is Expr, !.
R <- X :- R is X, !.
I have tried messing around with the multifile predicate, but I don't think that I understand how to use it.
However if the ch20_Ires.pl file is changed to:
:- 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, !.
everything works fine and I can execute my goal:
?- X <- residual_info(size).
X = 1.5421864522230475.
but I really want to separate my logic into more modules, instead of having everything in one file. And I want to be able to use this public/private-like system which modules are supposed to provide.
Are there anything I can rearrange in the code, or can I maybe solve my problem somehow with this multifile predicate?
And on a side note, do there exist any books that teaches stuff like using modules and other advanced prolog techniques? because I find it very hard to use the swi-prolog documentation and it is hard to find examples with google..
(<-)/2
predicate as a multifile predicate living in theuser
pseudo-module and with your other modules contributing with clauses for this multifile predicate. Simply adapt Carlo's answer to use:- multifile user:(<-)/2.
. But one (encapsulation) advantage of his original solution is that the(<-)/2
predicate is only visible inuser
unqualified if you load a module (intouser
) that exports it. – Paulo Moura