Difference between revisions of "VIP7 Construct examples"

From wiki.visual-prolog.com

m (link)
 
(50 intermediate revisions by 2 users not shown)
Line 1: Line 1:
This page contains a collection of examples for (mainly) the newer constructs found in VIP7.
This page contains a collection of basic examples for (mainly) the newer constructs found in VIP7.


 
=== Fact variables ===
===FACT VARIABLES===


Fact variables are the only mutable types in VIP.
Fact variables are the only mutable types in VIP.


'''Examples - "reminder- ordinary facts"'''
First, a reminder for ordinary facts:


<vip>facts
<vip>facts
ndb_int:(integer).  % a nondeterministic fact (0 to any number of values)
    ndb_int : (integer).  % a nondeterministic fact (0 to any number of values)
db_int:(integer,string) determ. % a deterministic fact (0 to 1 value)
    db_int : (integer,string) determ. % a deterministic fact (0 to 1 value)</vip>
</vip>
 
These types of fact are asserted and retracted.
These types of fact are asserted and retracted.


'''Examples - "fact variables"'''
'''Examples''' (fact variables)
 
<vip>facts
<vip>facts
zz_int:integer:=0.
    zz_int:integer := 0.
zz_fred:integer:=erroneous.
    zz_fred:integer := erroneous.


domains
domains
dom=dom(string,chaindb:ref).
    dom = dom(string,chaindb::ref).


facts
facts
zz_dom:dom:=erroneous.
    zz_dom : dom := erroneous.
 
clauses
clauses
pred():-
    pred() :-
zz_int:=7,
        zz_int := 7,
stdio::write("\n zz_int = ",zz_int), %will write "zz_int=7"
        stdio::write("\n zz_int = ", zz_int), %will write "zz_int = 7"
zz_int:=zz_int+20,
        zz_int := zz_int+20,
stdio::write("\n zz_int = ",zz_int), %will write "zz_int=27"
        stdio::write("\n zz_int = ", zz_int), %will write "zz_int = 27"
succeed.
        succeed.</vip>
</vip>
 
A fact variable is great for counting eg.
Fact variables are great for counting e.g.


<vip>predicates
<vip>predicates
pred:()=integer Count.
    how_many : () -> integer Count.
clauses
    how_many() = zz_int :-
        zz_int := 0,
        foreach some_nondeterm_fact_or_pred() do
            zz_int := zz_int+1
        end foreach.
 
clauses
clauses
pred()=_:-
    pred() :-
zz_int:=0,
      stdio::write("\n There are ", how_many(), " items").</vip>
some_nondeterm_fact_or_pred(),
zz_int:=zz_int+1,
fail.
pred()=zz_int.
</vip>


=== LISTS - FINDALL AND LIST COMPREHENSION  ===  
=== Lists - findall and list comprehension ===


findall has been depricated, so use the list comprehension construct.
See [[Lists and Recursion]]
<vp>findall()</vp> has been deprecated, so use the list comprehension construct.


'''Examples'''
'''Examples'''
<vip>facts
<vip>facts
ndb:(integer). %default is nondeterm for a fact
    ndb : (integer). %default is nondeterm for a fact
clauses
clauses
ndb(1).
    ndb(1).
ndb(2).
    ndb(2).
ndb(3).
    ndb(3).
....
    ....
ndb(10).
    ndb(10).
 
clauses
clauses
pred_old():-
    pred_old() :-
findall(X,ndb(X),List).
        findall(X,ndb(X),List).
%results in List = [1,2,3,4,5,6,7,8,9,10]
        %results in List = [1,2,3,4,5,6,7,8,9,10]
 
clauses
clauses
pred_new():-
    pred_new() :-
List=[X||ndb(X)].
        List = [ X || ndb(X) ].
%results in List = [1,2,3,4,5,6,7,8,9,10]
        %results in List = [1,2,3,4,5,6,7,8,9,10]
 
clauses
clauses
pred_filter():-
    pred_filter() :-
List=[X||ndb(X), X>6].
        List = [ X || ndb(X), X>6 ].
%results in List = [7,8,9,10]
        %results in List = [7,8,9,10]
 
    pred_filter() :-
        List = [ X || ndb(X), X mod 2 = 0 ].
        %results in List = [2,4,6,8,10]
 
    pred_filter() :-
        List = [ X || ndb(X), X mod 2 = 0, X<7 ].
        %results in List = [2,4,6]


pred_filter():-
    pred_filter() :-
List=[X||ndb(X), X mod 2=0].
        zz_int := 0,
%results in List = [2,4,6,8,10]
        List = [ X || ndb(X), X mod 2 = 0, X<7, zz_int := zz_int+1 ].
        %results in List = [2,4,6] and zz_int = 3.


pred_filter():-
    pred_filter() :-
List=[X||ndb(X), X mod 2=0, X<7].
        List = [ X || ndb(X), Y = pred2(X), Y>10 ].   %with pred2(X) = X^2.
%results in List = [2,4,6]
        %results in List = [4,5,6,7,8,9,10]
        %reason - X = 3 gives Y = 9 which is < 10.
pred_filter():-
zz_int:=0,
List=[X||ndb(X), X mod 2=0, X<7, zz_int:=zz_int+1].
%results in List = [2,4,6] and zz_int=3.


pred_filter():-
    pred_other() :-
List=[X||ndb(X), Y=pred2(X), Y>10].  %with pred2(X)=X^2.
        L = [1,2,3,4,5,6,7,8,9,10],
%results in List = [4,5,6,7,8,9,10]  
        LIST = [ X || X = list::getMember_nd(L)].
%reason - X=3 gives Y=9 which is < 10.
        %results in List = L
 
pred_other():-
    pred_other() :-
    L=[1,2,3,4,5,6,7,8,9,10],
        Primes =
LIST=[ X || X = list::getMember_nd(L)].
            [ X || X = std::fromto(1,300),
%results in List= L
                L1 = [ Y || Y = std::fromto(2,150) ],
</vip>
                tt(X,L1) ].
        %results in List = prime numbers, with:
 
class predicates
        tt : (integer,integer*) determ.
clauses
        tt(_X,[]) :- !.
        tt(X,[X|_]) :- !.
        tt(X,[Y|L]) :-
        X mod Y<>0,
        tt(X,L).</vip>


===IF THEN ELSE (CODE) ===  
=== if-then-else (code) ===


'''Examples'''
'''Examples'''


<vip>clauses
<vip>clauses
pred(X):-
    pred(X,Y) = Z :-
if X>0 then
        if X = 0 then
    stdio::write("\n X>0")  %the last line in each block has no comma
            Z = "x is zero"
else
        elseif X>0 then
    stdio::write("\n X<=0")
            if pred3(Y) = true then
end if.
                Z = "x>0 and pred(Y) is true"
            else
                Z = "x>0 and pred(Y) is false"
            end if %note, no comma here either
        else
            Z = "x <0"
        end if.</vip>
 
=== #if #then #else (directive for conditional compilation) ===


pred(X):-
'''Examples'''
if X>0 then
    stdio::write("\n X>0")
elseif X = 0 then
    stdio::write("\n X=0")
else
    stdio::write("\n X<0")
end if.


clauses
<vip>constants
pred(X,Y)=Z:-
    u64_con = 1.
if X=0 then
    int_con = 2.
    Z="x is zero"
    real_con = 3.
elseif X>0 then
if pred3(Y)=true then
Z="x>0 and pred(Y) is true"
else
Z="x>0 and pred(Y) is false"
end if  %note, no comma here either
else
Z="x <0"
end if.
</vip>


===#IF #THEN #ELSE (COMILER DIRECTIVE FOR CONDITIONAL COMPILATION)===
    compile_big_con = u64_con. %change this and then recompile.


'''Examples'''
#if compile_big_con = u64_con #then
<vip>
    predicates
constants
        pred : () -> unsigned64.
u64_con=1.
    clauses
int_con=2.
        pred() = U64 :-
real_con=3.
            U64 = 78766.


compile_big_con=u64_con. %change this and then recompile.
#elseif compile_big_con = int_con #then
    predicates
        pred : () -> integer.
    clauses
        pred() = Int :-
            Int = 20.


#if compile_big_con=u64_con #then
predicates
pred:()->unsigned64.
clauses
pred()=U64:-
U64=78766.
#elseif compile_big_con=int_con #then
predicates
pred:()->integer.
clauses
pred()=Int:-
Int=20.
#else
#else
predicates
    predicates
pred:(real [out]).
        pred : (real [out]).
clauses
    clauses
pred(0.766).
        pred(0.766).
#endif
 
</vip>
#endif</vip>
'''Note'''<br>
 
Code construct uses    '''if  - then''''''elseif  - then''''''else''''''end if''' <br>
'''Note'''
compiler directive uses '''#if - #then''', '''#elseif - #then''', '''#else''', '''#endif'''
Code construct uses    <vp>if  - then</vp><vp>elseif  - then</vp><vp>else</vp><vp>end if</vp>
<br>(just the "end if" is "different")
compiler directive uses <vp>#if - #then</vp>, <vp>#elseif - #then</vp>, <vp>#else</vp>, <vp>#endif</vp>
(just the "end if" is "different")


=== Trap and try/catch/finally ===


===TRAP AND TRY/CATCH/FINALLY ===
See [[Language Reference/Terms/Try-catch-finally|Try-catch-finally]]
Note, in <br>
Note, in [[Language Reference/Built-in entities/Predicates|Built-in entities/Predicates]]
http://wiki.visual-prolog.com/index.php?title=Language_Reference/Built-in_entities/Predicates
suggests using <vp>try-end try</vp> instead of <vp>trap(_,_,_)</vp>
use try-end try instead of trap


'''Example 1'''
'''Example 1'''
<vip>
 
pred_all():-
<vip>clauses
try
    pred_all() :-
call_pred_that_might_crash(0)
        try
catch ErrorNo do
            call_pred_that_might_crash(0)
call_own_exception_pred(ErrorNo)
        catch ErrorNo do
finally
            call_own_exception_pred(ErrorNo)
always_call_this_anyway()
        finally
end try.
            always_call_this_anyway()
        end try.


class predicates
class predicates
call_pred_that_might_crash:(integer).
    call_pred_that_might_crash : (integer).
call_own_exception_pred:(pointer ErrorNo).
    call_own_exception_pred : (pointer ErrorNo).
always_call_this_anyway:().
    always_call_this_anyway : ().
clauses
clauses
call_pred_that_might_crash(X):-
    call_pred_that_might_crash(X) :-
Y=9/X.
        Y = 9/X.


call_own_exception_pred(ErrorNo):-
    call_own_exception_pred(ErrorNo) :-
vpiCommonDialogs::note("crashed").
        vpiCommonDialogs::note("crashed").
 
    always_call_this_anyway() :-
        vpiCommonDialogs::note("finally reached").</vip>


always_call_this_anyway():-
vpiCommonDialogs::note("finally reached").
</vip>
'''Example 2'''
'''Example 2'''
<vip>
 
pred_some():-
<vip>clauses
try
    pred_some() :-
call_pred_that_might_crash(0)
        try
finally
            call_pred_that_might_crash(0)
always_call_this_anyway()
        finally
end try.
            always_call_this_anyway()
</vip>
        end try.</vip>
 
% in this case, VIP will automatically pop up its exception dialog
% in this case, VIP will automatically pop up its exception dialog


'''Example 3'''
'''Example 3'''
<vip>
pred_some():-
try
call_pred_that_might_crash(0)
catch ErrorNo do
call_own_exception_pred(ErrorNo)
end try.
</vip>
'''Example 4''' - illegal - it must have a "catch" or "finally"
<vip>
pred_illegal():-
try
call_pred_that_might_crash(0)
end try.
</vip>


===64 BIT NUMBERS===  
<vip>clauses
    pred_some() :-
        try
            call_pred_that_might_crash(0)
        catch ErrorNo do
            call_own_exception_pred(ErrorNo)
        end try.</vip>
 
'''Example 4''' - illegal - it must have a <vp>catch</vp> or <vp>finally</vp>
 
<vip>clauses
    pred_illegal() :-
        try
            call_pred_that_might_crash(0)
        end try.</vip>
 
=== Foreach ===
 
See [[Language Reference/Terms/Foreach|Foreach]]
 
=== 64 bit numbers - history ===
 
Up to VIP7.1, integer64 etc were defined as:
 
<vip>domains
    unsigned64 = unsigned64(unsigned32 Low, unsigned32 High).
    integer64 = integer64(unsigned32 Low, integer32 High).</vip>
 
In VIP7.2 these have been renamed:
 
<vip>domains
    unsigned64_struct = unsigned64(unsigned Low, unsigned High).
    integer64_struct = integer64(unsigned Low, integer High).</vip>
 
So, for example, in VIP7.1:
 
<vip>predicates
    getFileProperties : (
        string FileName,
        fileSystem_api::fileAttributes Attributes,
        fileSystem_api::fileSize Size,
        core::gmtTimeValue Creation,
        core::gmtTimeValue LastAccess,
        core::gmtTimeValue LastChange)
        procedure (i,o,o,o,o,o).</vip>
 
if you needed use (and write) '''fileSize''' and times, you would have to have done some juggling (such as converting them to real numbers).
 
To generate a 64 bit random number:
 
<vip>predicates %before VIP7.2
    gen64 : () -> unsigned64.
clauses
    gen64() = U64 :-
        N = 2^32,
        Low = math::random(N+0),
        High = math::random(N+0),
        U64 = unsigned64(Low,High).</vip>
 
and possibly you would have needed (e.g.) '''math::add''':
 
<vip>predicates
    add : (core::unsigned64 Augend, core::unsigned64 Addend) -> core::unsigned64 Sum</vip>
 
It's now totally straightforward in VIP7.2 - just treat 64 bit numbers like any other number. You may also want these conversions - found in '''core::''' - for old code (this snippet is stolen from [http://discuss.visual-prolog.com/viewtopic.php?t=7927 Thomas' post])
 
<vip>predicates
    toUnsigned64 : (unsigned64_struct) -> unsigned64.
    fromUnsigned64 : (unsigned64) -> unsigned64_struct.
    toInteger64 : (integer64_struct) -> integer64.
    fromInteger64 : (integer64) -> integer64_struct.</vip>
 
And just for reference:
* [[Language Reference/Built-in_entities/Domains#integer|integer]] range = -2^31 to +2^31-1 = -2147483648 .. 2147483647
* [[Language Reference/Built-in_entities/Domains#unsigned|unsigned]]  range = 0 to (2^32)-1 = 4294967295
* [[Language Reference/Built-in_entities/Domains#integer64|integer64]] range = -2^63 to 2^63
* [[Language Reference/Built-in_entities/Domains#unsigned64|unsigned64]] range = 0 to (2^64)-1 = 18446744073709551615 ( = 1.844..E19)
 
=== Polymorphic Domains ===
 
See {{lang|Objects and Polymorphism|Objects and Polymorphism}}
 
First, check out the definitions - <vp>core::tuple{}</vp>. And while you're there, just below, see <vp>core::predicate{}</vp> and <vp>core::function{}</vp>, then followed by <vp>comparator{A}</vp> and <vp>list{A}</vp>.
 
The domains in class <vp>list::</vp> are polymorphic, but you can define your own polymorphic domains. Here are some examples:
 
<vip>domains
    poly_dom{A,B} = poly_def(A,B).</vip>
 
When you use it in your code, A and B can be any other domain.  The domain name is <vp>poly_dom{A,B}</vp>, and you reference it you must use its whole name (not just <vp>poly_dom</vp>) e.g.
 
<vip>domains
    joe{A,B} = poly_dom{A,B}*.
/* the next two lines are illegal
    poly_dom{A,B} = poly_def(A,B)*.
    poly_dom{A,A} = poly_def(A,A).
*/
    fred{A,B} = fred(poly_dom{A,B},integer).
 
    maybe_silly_dom{A,B} =
        silly2(A,B);
        silly(A);
        pd(poly_dom{A,B});
        poly_dom(A,B);%IS NOT THE SAME POLY_DOM!! (notice no braces)
        s(string).
 
    another{A} =
        i(integer);
        s(string);
        a(A);
        self(another({A}).
 
facts
    zz_poly_dom:poly_dom{integer,integer} := erroneous.
 
class predicates
    p_morphic_test : ().
clauses
    p_morphic_test() :-
        zz_poly_dom := poly_def(1,5),
        call_pd(zz_poly_dom),
        fail.
    p_morphic_test() :-
        PD = poly_def(1,["an example","or two"]),
        call_pd(PD),
        fail.
    p_morphic_test() :-
        Q = [poly_def(X, Y) || X = std::fromTo(1, 4), Y = std::fromTo(1, 5)],
        stdio::write("\n",Q),
        fail.
    p_morphic_test().


class predicates
    call_pd : (poly_dom{A,B}).
clauses
    call_pd(POLY_DOM) :-
        stdio::write("\n",POLY_DOM),
        fail.
    call_pd(poly_def(A,B)) :- %note this is POLY_DEF
        stdio::write("\n",A,B),
        fail.
    call_pd(_).</vip>


=== Properties ===


===PROPERTIES===
Properties in a class are used almost identically to fact variables, but properties can be set directly (from another class), without having to declare a public predicate to make the change.
Properties in a class are used almost identically to fact variables, but properties can be set directly (from another class), without having to declare a public predicate to make the change.


'''Example'''
'''Example'''
<vip>interface fred
    domains
        complete_dom = is_complete;
                    not_complete.
    properties
        prop_complete : complete_dom.
end interface fred</vip>
In '''fred.pro''':
<vip>
<vip>
interface fred
implement fred
domains
complete_dom=is_complete;
not_complete.
properties
prop_complete : complete_dom.
end interface fred
</vip>
In fred.pro:
<vip>
facts
facts
zz_complete:complete_dom:=erroneous.
    zz_complete:complete_dom := erroneous.


clauses %for the property
clauses %for the property
prop_complete()=zz_complete. %get
    prop_complete() = zz_complete. %get
prop_complete(COMPLETE):-zz_complete:=COMPLETE. %set
    prop_complete(COMPLETE) :- zz_complete := COMPLETE. %set</vip>
</vip>
 


In some other class that calls class fred:
In some other class that calls class fred:
<vip>implement other
    open fred
clauses
    pred() :-
        Fred = fred::new(),
        Fred:prop_complete := is_complete,% to set the value
        Value = Fred:prop_complete, !. %get</vip>
=== Comparators and compare ===
First, look at the definition of '''core::comparator''':
<vip>domains
    comparator{T} = function{T, T, compareResult}.</vip>
<vp>compareResult</vp>'s definition can is found here: [[Language Reference/Built-in entities/Domains#compareResult|compareResult]]
'''Examples'''
<vip>
class predicates
    p_compare_test : ().
clauses
    p_compare_test() :-
        CompareResult = compare(7,2).
        %will bind CompareResult to '''greater()'''
        %(because 7 > 2)
    p_compare_test() :-
        CompareResult = compare(2,2).
        %will bind CompareResult to '''equal()'''
    p_compare_test() :-
        CompareResult = compare("a","z").
        %will bind CompareResult to '''less()'''</vip>
But you may wish to check your own domains to see which is "greater" - and of course you must define this yourself, by defining your own predicate as a '''core::comparator'''
Here is a simple domain in which only the integer parts of the variables are checked to see which is greater:
<vip>domains
    s = s(string,integer).
class predicates
    compare_it: core::comparator{s}.
clauses
    compare_it(A,B) = CompareResult :- %since this is a core::function(T,T,compareResult)
        A = s(_,I),
        B = s(_,J),
        if I<J then
            CompareResult = less()
        elseif I = J then
            CompareResult = equal()
        else
            CompareResult = greater()
        end if.
class predicates
    p_compare_test : ().
clauses
    p_compare_test() :-
        S1 = s("abc",7),
        S2 = s("fred",9),
        CompareResult = compare_it(S1,S2),
        %will give CompareResult = less, since 7<9.</vip>
...a bit pointless since the string part of the variables have been ignored, but it is easy to see how to expand <vp>compare_it()</vp> to your own needs.
=== list::sortby example using Comparator===
list::sortby also uses Compareresult.<br>
Say you have the following domain and fact:<br>
<vip>
domains
triple=triple(string,gmttimevalue,integer).
facts
zz_triples:triple:=erroneous.
</vip><br>
zz_triples is populated, but it needs to be sorted by date/time. Then:
<vip>
<vip>
implement other
open fred
clauses
clauses
pred():-
test():-
Fred=fred::new(),
zz_triples:=list::sortby(cp,zz_triples).
Fred:prop_complete:=is_complete,% to set the value
 
Value=Fred:prop_complete,!. %get
predicates
cp:core::comparator{triple}.
clauses
cp(A,B)=CompareResult:-
A=triple(_,ATv,_),
B=triple(_,BTv,_),
GMTA=gmttime::new(Atv),
GMTB=gmttime::new(Btv),
if GMTA:before(GMTB) then
CompareResult=less
else
CompareResult=greater
end if,!.
 
</vip>
or
<vip>
test():-
zz_triples:=list::sortBy(
    {(A,B)=CompareResult:-
A=triple(_,ATv,_),
B=triple(_,BTv,_),
GMTA=gmttime::new(Atv),
GMTB=gmttime::new(Btv),
if GMTA:before(GMTB) then
CompareResult=less
else
CompareResult=greater
end if},
          zz_triples).
</vip>
</vip>
=== list::isMemberBy example using Comparator===


===COMPARATORS AND COMPARE===
list::isMemberBy also uses Compareresult.<br>
<vip>
domains
intx=integer.
some_struct=fred(integer*);point(pointer).
dom=dom(intx,some_struct).
predicates
test:().
clauses
test():-
Some_struct=fred([]),
Dom1=dom(1,Some_struct),
Dom2=dom(4,Some_struct),
Dom3=dom(9,Some_struct),
Dom4=dom(7,Some_struct),
Doms=[Dom1,Dom2,Dom3,Dom4],
    if list::isMemberBy(comp,4,Doms) then
    stdio::write("Dom(4,_) found")
else
stdio::write("Dom not found")
end if.
predicates
    comp:comparator{intx,dom}.
clauses
    comp(Intx,DOM)=equal:-
    DOM=dom(Intx,_),!.
    comp(_,_)=greater.
</vip>
Also see
[http://wiki.visual-prolog.com/index.php?title=Language_Reference/Terms#Sorting http://wiki.visual-prolog.com/index.php?title=Language_Reference/Terms#Sorting]
 
=== More on core::function and core::predicate ===
 
Again, please check out <vp>core::function</vp>.  <vp>core::predicate</vp> is essentially the same, but does not return a value.
 
'''Example 1'''
 
<vip>class predicates
    two_times:function{integer,integer}.
% or    two_times: core::function{integer,integer}.
clauses
    two_times(A) = 2*A.
class predicates
    p_function : ().
clauses
    p_function() :-
        Z = two_times(2),
        %binds Z to 4</vip>
 
'''Example 2'''


<vip>domains
    fred_dom{A,B} = predicate{A,B}.
% or    fred_dom{A,B} = core::predicate{A,B}.
class predicates
    fred_pred: fred_dom{A,B}.
clauses
    fred_pred(A,B) :-
        stdio::write("\n",A," ",B).
class predicates
    p_pred : ().
clauses
    p_pred() :-
        fred_pred("one",2).</vip>
'''Example 3'''
<vip>class predicates
    add_func: function{integer,integer}.
clauses
    add_func(B) = B+1.
class predicates
    p_function : ().
clauses
    p_function() :-
        X = add_func(5),
        %X is bound to 6</vip>
=== Anonymous predicates ===
See [[Language Reference/Terms/Anonymous Predicates|Anonymous Predicates]]
'''Examples'''
<vip>clauses
    run() :-
        Anon = {() = 9},
        K = Anon().
        %results in K = 9
    run() :-
        Anon = { = 88},
        K = Anon().
        %results in K = 88.
    run() :-
        Anon = {(A,B) = A+B},
        K = Anon(4,8),
        %results in K = 12.
    run() :-
        Anon = {
            (A,B) = C :-
            R = math::random(7),
            C = A+B+R,
            stdio::wRite("RRRR = ",R)
            },
        K = Anon(4,8).
        %results in K = 12 + a random number <7
    run() :-
        Anon = { = f_abc(3)},
        K = Anon(),
        stdio::write("\nI = { = f_abc(3)} gives ",K),
        fail.
    run().</vip>
=== Threads ===
To start a thread:
<vip>clauses
    pred() :-
        _ = thread::start(fred).
predicates
    fred : ().
clauses
    fred() :- .....</vip>
fred can have no arguments, so no argument brackets are allowed:
<vip>    _ = thread::start(fred())</vip>
is illegal.
Using [[Language Reference/Terms/Anonymous Predicates|Anonymous Predicates]] is rather simple to pass arguments to thread:
<vip>clauses
    pred(X) :-
        _ = thread::start( { :- fred(X) } ).
predicates
    fred : (integer K).
clauses
    fred(K) :-
        ...</vip>


===ANONYMOUS PREDICATES===
[[Category:Examples]]

Latest revision as of 10:20, 4 July 2017

This page contains a collection of basic examples for (mainly) the newer constructs found in VIP7.

Fact variables

Fact variables are the only mutable types in VIP.

First, a reminder for ordinary facts:

facts
    ndb_int : (integer).  % a nondeterministic fact (0 to any number of values)
    db_int : (integer,string) determ. % a deterministic fact (0 to 1 value)

These types of fact are asserted and retracted.

Examples (fact variables)

facts
    zz_int:integer := 0.
    zz_fred:integer := erroneous.
 
domains
    dom = dom(string,chaindb::ref).
 
facts
    zz_dom : dom := erroneous.
 
clauses
    pred() :-
        zz_int := 7,
        stdio::write("\n zz_int = ", zz_int), %will write "zz_int = 7"
        zz_int := zz_int+20,
        stdio::write("\n zz_int = ", zz_int), %will write "zz_int = 27"
        succeed.

Fact variables are great for counting e.g.

predicates
    how_many : () -> integer Count.
clauses
    how_many() = zz_int :-
        zz_int := 0,
        foreach some_nondeterm_fact_or_pred() do
            zz_int := zz_int+1
        end foreach.
 
clauses
    pred() :-
       stdio::write("\n There are ", how_many(), " items").

Lists - findall and list comprehension

See Lists and Recursion findall() has been deprecated, so use the list comprehension construct.

Examples

facts
    ndb : (integer). %default is nondeterm for a fact
clauses
    ndb(1).
    ndb(2).
    ndb(3).
    ....
    ndb(10).
 
clauses
    pred_old() :-
        findall(X,ndb(X),List).
        %results in List = [1,2,3,4,5,6,7,8,9,10]
 
clauses
    pred_new() :-
        List = [ X || ndb(X) ].
        %results in List = [1,2,3,4,5,6,7,8,9,10]
 
clauses
    pred_filter() :-
        List = [ X || ndb(X), X>6 ].
        %results in List = [7,8,9,10]
 
    pred_filter() :-
        List = [ X || ndb(X), X mod 2 = 0 ].
        %results in List = [2,4,6,8,10]
 
    pred_filter() :-
        List = [ X || ndb(X), X mod 2 = 0, X<7 ].
        %results in List = [2,4,6]
 
    pred_filter() :-
        zz_int := 0,
        List = [ X || ndb(X), X mod 2 = 0, X<7, zz_int := zz_int+1 ].
        %results in List = [2,4,6] and zz_int = 3.
 
    pred_filter() :-
        List = [ X || ndb(X), Y = pred2(X), Y>10 ].   %with pred2(X) = X^2.
        %results in List = [4,5,6,7,8,9,10]
        %reason - X = 3 gives Y = 9 which is < 10.
 
    pred_other() :-
        L = [1,2,3,4,5,6,7,8,9,10],
        LIST = [ X || X = list::getMember_nd(L)].
        %results in List = L
 
    pred_other() :-
        Primes =
            [ X || X = std::fromto(1,300),
                L1 = [ Y || Y = std::fromto(2,150) ],
                tt(X,L1) ].
        %results in List = prime numbers, with:
 
class predicates
        tt : (integer,integer*) determ.
clauses
        tt(_X,[]) :- !.
        tt(X,[X|_]) :- !.
        tt(X,[Y|L]) :-
        X mod Y<>0,
        tt(X,L).

if-then-else (code)

Examples

clauses
    pred(X,Y) = Z :-
        if X = 0 then
            Z = "x is zero"
        elseif X>0 then
            if pred3(Y) = true then
                Z = "x>0 and pred(Y) is true"
            else
                Z = "x>0 and pred(Y) is false"
            end if  %note, no comma here either
        else
            Z = "x <0"
        end if.

#if #then #else (directive for conditional compilation)

Examples

constants
    u64_con = 1.
    int_con = 2.
    real_con = 3.
 
    compile_big_con = u64_con. %change this and then recompile.
 
#if compile_big_con = u64_con #then
    predicates
        pred : () -> unsigned64.
    clauses
        pred() = U64 :-
            U64 = 78766.
 
#elseif compile_big_con = int_con #then
    predicates
        pred : () -> integer.
    clauses
        pred() = Int :-
            Int = 20.
 
#else
    predicates
        pred : (real [out]).
    clauses
        pred(0.766).
 
#endif

Note Code construct uses if  - then, elseif  - then, else, end if compiler directive uses #if - #then, #elseif - #then, #else, #endif (just the "end if" is "different")

Trap and try/catch/finally

See Try-catch-finally Note, in Built-in entities/Predicates suggests using try-end try instead of trap(_,_,_)

Example 1

clauses
    pred_all() :-
        try
            call_pred_that_might_crash(0)
        catch ErrorNo do
            call_own_exception_pred(ErrorNo)
        finally
            always_call_this_anyway()
        end try.
 
class predicates
    call_pred_that_might_crash : (integer).
    call_own_exception_pred : (pointer ErrorNo).
    always_call_this_anyway : ().
clauses
    call_pred_that_might_crash(X) :-
        Y = 9/X.
 
    call_own_exception_pred(ErrorNo) :-
        vpiCommonDialogs::note("crashed").
 
    always_call_this_anyway() :-
        vpiCommonDialogs::note("finally reached").

Example 2

clauses
    pred_some() :-
        try
            call_pred_that_might_crash(0)
        finally
            always_call_this_anyway()
        end try.

% in this case, VIP will automatically pop up its exception dialog

Example 3

clauses
    pred_some() :-
        try
            call_pred_that_might_crash(0)
        catch ErrorNo do
            call_own_exception_pred(ErrorNo)
        end try.

Example 4 - illegal - it must have a catch or finally

clauses
    pred_illegal() :-
        try
            call_pred_that_might_crash(0)
        end try.

Foreach

See Foreach

64 bit numbers - history

Up to VIP7.1, integer64 etc were defined as:

domains
    unsigned64 = unsigned64(unsigned32 Low, unsigned32 High).
    integer64 = integer64(unsigned32 Low, integer32 High).

In VIP7.2 these have been renamed:

domains
    unsigned64_struct = unsigned64(unsigned Low, unsigned High).
    integer64_struct = integer64(unsigned Low, integer High).

So, for example, in VIP7.1:

predicates
     getFileProperties : (
        string FileName,
        fileSystem_api::fileAttributes Attributes,
        fileSystem_api::fileSize Size,
        core::gmtTimeValue Creation,
        core::gmtTimeValue LastAccess,
        core::gmtTimeValue LastChange)
        procedure (i,o,o,o,o,o).

if you needed use (and write) fileSize and times, you would have to have done some juggling (such as converting them to real numbers).

To generate a 64 bit random number:

predicates %before VIP7.2
    gen64 : () -> unsigned64.
clauses
    gen64() = U64 :-
        N = 2^32,
        Low = math::random(N+0),
        High = math::random(N+0),
        U64 = unsigned64(Low,High).

and possibly you would have needed (e.g.) math::add:

predicates
    add : (core::unsigned64 Augend, core::unsigned64 Addend) -> core::unsigned64 Sum

It's now totally straightforward in VIP7.2 - just treat 64 bit numbers like any other number. You may also want these conversions - found in core:: - for old code (this snippet is stolen from Thomas' post)

predicates
    toUnsigned64 : (unsigned64_struct) -> unsigned64.
    fromUnsigned64 : (unsigned64) -> unsigned64_struct.
    toInteger64 : (integer64_struct) -> integer64.
    fromInteger64 : (integer64) -> integer64_struct.

And just for reference:

  • integer range = -2^31 to +2^31-1 = -2147483648 .. 2147483647
  • unsigned range = 0 to (2^32)-1 = 4294967295
  • integer64 range = -2^63 to 2^63
  • unsigned64 range = 0 to (2^64)-1 = 18446744073709551615 ( = 1.844..E19)

Polymorphic Domains

See Objects and Polymorphism

First, check out the definitions - core::tuple{}. And while you're there, just below, see core::predicate{} and core::function{}, then followed by comparator{A} and list{A}.

The domains in class list:: are polymorphic, but you can define your own polymorphic domains. Here are some examples:

domains
    poly_dom{A,B} = poly_def(A,B).

When you use it in your code, A and B can be any other domain. The domain name is poly_dom{A,B}, and you reference it you must use its whole name (not just poly_dom) e.g.

domains
    joe{A,B} = poly_dom{A,B}*.
/* the next two lines are illegal
    poly_dom{A,B} = poly_def(A,B)*.
    poly_dom{A,A} = poly_def(A,A).
*/
    fred{A,B} = fred(poly_dom{A,B},integer).
 
    maybe_silly_dom{A,B} =
        silly2(A,B);
        silly(A);
        pd(poly_dom{A,B});
        poly_dom(A,B);%IS NOT THE SAME POLY_DOM!! (notice no braces)
        s(string).
 
    another{A} =
        i(integer);
        s(string);
        a(A);
        self(another({A}).
 
facts
    zz_poly_dom:poly_dom{integer,integer} := erroneous.
 
class predicates
    p_morphic_test : ().
clauses
    p_morphic_test() :-
        zz_poly_dom := poly_def(1,5),
        call_pd(zz_poly_dom),
        fail.
    p_morphic_test() :-
        PD = poly_def(1,["an example","or two"]),
        call_pd(PD),
        fail.
    p_morphic_test() :-
        Q = [poly_def(X, Y) || X = std::fromTo(1, 4), Y = std::fromTo(1, 5)],
        stdio::write("\n",Q),
        fail.
    p_morphic_test().
 
class predicates
    call_pd : (poly_dom{A,B}).
clauses
    call_pd(POLY_DOM) :-
        stdio::write("\n",POLY_DOM),
        fail.
    call_pd(poly_def(A,B)) :- %note this is POLY_DEF
        stdio::write("\n",A,B),
        fail.
    call_pd(_).

Properties

Properties in a class are used almost identically to fact variables, but properties can be set directly (from another class), without having to declare a public predicate to make the change.

Example

interface fred
    domains
        complete_dom = is_complete;
                     not_complete.
    properties
        prop_complete : complete_dom.
end interface fred

In fred.pro:

implement fred
facts
    zz_complete:complete_dom := erroneous.
 
clauses %for the property
    prop_complete() = zz_complete. %get
    prop_complete(COMPLETE) :- zz_complete := COMPLETE. %set


In some other class that calls class fred:

implement other
    open fred
clauses
    pred() :-
        Fred = fred::new(),
        Fred:prop_complete := is_complete,% to set the value
        Value = Fred:prop_complete, !. %get

Comparators and compare

First, look at the definition of core::comparator:

domains
    comparator{T} = function{T, T, compareResult}.

compareResult's definition can is found here: compareResult

Examples

class predicates
    p_compare_test : ().
clauses
    p_compare_test() :-
        CompareResult = compare(7,2).
        %will bind CompareResult to '''greater()'''
        %(because 7 > 2)
    p_compare_test() :-
        CompareResult = compare(2,2).
        %will bind CompareResult to '''equal()'''
    p_compare_test() :-
        CompareResult = compare("a","z").
        %will bind CompareResult to '''less()'''

But you may wish to check your own domains to see which is "greater" - and of course you must define this yourself, by defining your own predicate as a core::comparator Here is a simple domain in which only the integer parts of the variables are checked to see which is greater:

domains
    s = s(string,integer).
 
class predicates
    compare_it: core::comparator{s}.
clauses
    compare_it(A,B) = CompareResult :- %since this is a core::function(T,T,compareResult)
        A = s(_,I),
        B = s(_,J),
        if I<J then
            CompareResult = less()
        elseif I = J then
            CompareResult = equal()
        else
            CompareResult = greater()
        end if.
 
class predicates
    p_compare_test : ().
clauses
    p_compare_test() :-
        S1 = s("abc",7),
        S2 = s("fred",9),
        CompareResult = compare_it(S1,S2),
        %will give CompareResult = less, since 7<9.

...a bit pointless since the string part of the variables have been ignored, but it is easy to see how to expand compare_it() to your own needs.

list::sortby example using Comparator

list::sortby also uses Compareresult.

Say you have the following domain and fact:

domains
	triple=triple(string,gmttimevalue,integer).
facts
	zz_triples:triple:=erroneous.


zz_triples is populated, but it needs to be sorted by date/time. Then:

clauses
	test():-
		zz_triples:=list::sortby(cp,zz_triples).
 
predicates
	cp:core::comparator{triple}.
clauses
	cp(A,B)=CompareResult:-
		A=triple(_,ATv,_),
		B=triple(_,BTv,_),
		GMTA=gmttime::new(Atv),
		GMTB=gmttime::new(Btv),
		if GMTA:before(GMTB) then
			CompareResult=less
		else
			CompareResult=greater
		end if,!.

or

	test():-
		zz_triples:=list::sortBy(
    			{(A,B)=CompareResult:-
				A=triple(_,ATv,_),
				B=triple(_,BTv,_),
				GMTA=gmttime::new(Atv),
				GMTB=gmttime::new(Btv),
				if GMTA:before(GMTB) then
					CompareResult=less
				else
					CompareResult=greater
				end if},
	           	zz_triples).

list::isMemberBy example using Comparator

list::isMemberBy also uses Compareresult.

domains
	intx=integer.
	some_struct=fred(integer*);point(pointer).
	dom=dom(intx,some_struct).
predicates
	test:().
clauses
	test():-
		Some_struct=fred([]),
		Dom1=dom(1,Some_struct),
		Dom2=dom(4,Some_struct),
		Dom3=dom(9,Some_struct),
		Dom4=dom(7,Some_struct),
		Doms=[Dom1,Dom2,Dom3,Dom4],
    		if list::isMemberBy(comp,4,Doms) then
    			stdio::write("Dom(4,_) found")
		else
			stdio::write("Dom not found")
		end if.
predicates
    comp:comparator{intx,dom}.
clauses
    comp(Intx,DOM)=equal:-
    	DOM=dom(Intx,_),!.
    comp(_,_)=greater.

Also see http://wiki.visual-prolog.com/index.php?title=Language_Reference/Terms#Sorting

More on core::function and core::predicate

Again, please check out core::function. core::predicate is essentially the same, but does not return a value.

Example 1

class predicates
    two_times:function{integer,integer}.
% or    two_times: core::function{integer,integer}.
clauses
    two_times(A) = 2*A.
class predicates
    p_function : ().
clauses
    p_function() :-
        Z = two_times(2),
        %binds Z to 4

Example 2

domains
    fred_dom{A,B} = predicate{A,B}.
% or    fred_dom{A,B} = core::predicate{A,B}.
 
class predicates
    fred_pred: fred_dom{A,B}.
clauses
    fred_pred(A,B) :-
        stdio::write("\n",A," ",B).
 
class predicates
    p_pred : ().
clauses
    p_pred() :-
        fred_pred("one",2).

Example 3

class predicates
    add_func: function{integer,integer}.
clauses
    add_func(B) = B+1.
 
class predicates
    p_function : ().
clauses
    p_function() :-
        X = add_func(5),
        %X is bound to 6

Anonymous predicates

See Anonymous Predicates

Examples

clauses
    run() :-
        Anon = {() = 9},
        K = Anon().
        %results in K = 9
    run() :-
        Anon = { = 88},
        K = Anon().
        %results in K = 88.
    run() :-
        Anon = {(A,B) = A+B},
        K = Anon(4,8),
        %results in K = 12.
    run() :-
        Anon = {
            (A,B) = C :-
            R = math::random(7),
            C = A+B+R,
            stdio::wRite("RRRR = ",R)
            },
        K = Anon(4,8).
        %results in K = 12 + a random number <7
 
    run() :-
        Anon = { = f_abc(3)},
        K = Anon(),
        stdio::write("\nI = { = f_abc(3)} gives ",K),
        fail.
    run().

Threads

To start a thread:

clauses
    pred() :-
        _ = thread::start(fred).
 
predicates
    fred : ().
clauses
    fred() :- .....

fred can have no arguments, so no argument brackets are allowed:

    _ = thread::start(fred())

is illegal.

Using Anonymous Predicates is rather simple to pass arguments to thread:

clauses
    pred(X) :-
        _ = thread::start( { :- fred(X) } ).
 
predicates
    fred : (integer K).
clauses
    fred(K) :-
        ...