tags:

views:

66

answers:

3

I am trying to create a custom enumeration via a series of facts.

greater(X,Y) :- less (Y,X).

less(a,b).
less(b,c).
less(c,d).

This works fine, however there is significant repetition.

I'm trying to cut that down. Is there a way to use an array for a simple linear series of facts via a transformation?

transform([a,b,c,d])

resulting in the same less definitions.

I have already created a "less" definition that uses an array and the nextto/member function to test, however I cannot add exceptions or equivalent cases like I could with individual declarations. Hence my interest in shortcutting the simple case definition, and then the desire to supplement it with more definitions.

This reminds me of where defmacro in lisp is useful.

Thanks.

Edit:

I was able to generate one series using assert. It successfully defines everything, but returns an error. I get the impression this isn't the correct method.

set_less([]).
set_less([X,Y|L]):- assert( myless(X,Y) ) , set_less([Y|L]).
:- set_less([a,b,c,d]).

Output: 
Goal (directive) failed: user:set_less([a, b, c, d])

?- listing.

:- dynamic myless/2.

myless(a, b).
myless(b, c).
myless(c, d).

Second Edit:

mylist([a,b,c,d]).

set_less([]).
set_less([_]).  ----- Key!
set_less([X,Y|L]):- assert( myless(X,Y) ) , set_less([Y|L]).
:- set_less([a,b,c,d]).

That does work! Is this a good way to define custom enumerations? I see it works now, thanks!

+1  A: 

I have already created a "less" definition that uses an array and the nextto/member function to test, however I cannot add exceptions or equivalent cases like I could with individual declarations.

You could still add your "exceptions and equivalent cases" before your "array definition", just as you would add them before a series of facts, couldn't you?

Or perhaps you want to experiment with univ, the =.. operator.

pfctdayelise
I suppose I could add them before the array oriented version. I didn't know about the =.. operator!
Demosthenex
+1  A: 
term_expansion(list_enumerate(Name,List), [mylist(Name,List)|Flist]) :-
    list_enumerate_to_list(List, Flist).

list_enumerate_to_list([], []).
list_enumerate_to_list([_], []).
list_enumerate_to_list([X,Y|Xs], [myless(X,Y)|Ys]) :-
        list_enumerate_to_list([Y|Xs], Ys).

list_enumerate(test,[a1,b1,c1,d1]).
list_enumerate(first,[a,b,c,d]).
list_enumerate(second,[f,e,g,h]).

testless(X,Y) :- myless(X,Y).
testless(X,Y) :- myless(X,Z) , testless(Z,Y).

Output---------------------------------------------------------------

?- listing.


myless(a1, b1).
myless(b1, c1).
myless(c1, d1).
myless(a, b).
myless(b, c).
myless(c, d).
myless(f, e).
myless(e, g).
myless(g, h).

?- testless(a1,c1).
true ;
false.

?- testless(X,c1).
X = b1 ;
X = a1 ;
false.

That works! Thanks to soupdragon on #prolog on freenode.

There are a few warnings at startup, but they can be ignored.

Demosthenex
+1  A: 

If you want a total order of your items then you can also just map them to natural numbers at consult/compile time. When doing the comparison then just look up the numbers and compare them. This should be a lot faster if you have a lot of items.

Something like this:

% Key generation
make_keys(List, Keys) :-
    make_keys(List, 0, Keys).

make_keys([], _, []).
make_keys([El | Els], Index, [mykey(El, Index) | Ks]) :-
    NewIndex is Index + 1,
    make_keys(Els, NewIndex, Ks).

% Mapping ordering/1 to a set of mykey/2
term_expansion(ordering(List), Clauses) :-
    make_keys(List, Clauses).

% Ordering
ordering([first, second, third, fourth, fifth]).

% Comparison by looking at the keys
greater_than(X, Y) :-
    mykey(X, XK),
    mykey(Y, YK),
    XK > YK.
Kaarel
Wow! You're absolutely right that would be faster. I was enumerating because I couldn't use an predefined type. My only concern here is the potential for key collisions when I'm using multiple parallel enumerations. Thanks for the great idea!
Demosthenex