Difference between revisions of "VIP7 Construct examples"

From wiki.visual-prolog.com

m (link)
 
(34 intermediate revisions by 2 users not shown)
Line 5: Line 5:
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)</vip>
     db_int : (integer,string) determ. % a deterministic fact (0 to 1 value)</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.</vip>
         succeed.</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
clauses
     pred()=_:-
     how_many() = zz_int :-
         zz_int:=0,
         zz_int := 0,
         some_nondeterm_fact_or_pred(),
         foreach some_nondeterm_fact_or_pred() do
             zz_int:=zz_int+1,
             zz_int := zz_int+1
            fail.
        end foreach.
     pred()=zz_int.</vip>
 
clauses
     pred() :-
      stdio::write("\n There are ", how_many(), " items").</vip>


=== Lists - findall and list comprehension ===
=== Lists - findall and list comprehension ===


See [http://wiki.visual-prolog.com/index.php?title=Lists_and_Recursion Lists and Recursion]<br>
See [[Lists and Recursion]]
<vp>findall()</vp> has been depricated, so use the list comprehension construct.
<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).
Line 58: Line 63:
     ....
     ....
     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():-
     pred_filter() :-
         List=[X||ndb(X), X mod 2=0].
         List = [ X || ndb(X), X mod 2 = 0 ].
         %results in List = [2,4,6,8,10]
         %results in List = [2,4,6,8,10]


     pred_filter():-
     pred_filter() :-
         List=[X||ndb(X), X mod 2=0, X<7].
         List = [ X || ndb(X), X mod 2 = 0, X<7 ].
         %results in List = [2,4,6]
         %results in List = [2,4,6]


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


     pred_filter():-
     pred_filter() :-
         List=[X||ndb(X), Y=pred2(X), Y>10].  %with pred2(X)=X^2.
         List = [ X || ndb(X), Y = pred2(X), Y>10 ].  %with pred2(X) = X^2.
         %results in List = [4,5,6,7,8,9,10]
         %results in List = [4,5,6,7,8,9,10]
         %reason - X=3 gives Y=9 which is < 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():-
     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) ],
                tt(X,L1) ].
         %results in List = prime numbers, with:


    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
class predicates
         tt:(integer,integer*) determ.
         tt : (integer,integer*) determ.
clauses
clauses
         tt(_X,[]):-!.
         tt(_X,[]) :- !.
         tt(X,[X|_]):-!.
         tt(X,[X|_]) :- !.
         tt(X,[Y|L]):-
         tt(X,[Y|L]) :-
X mod Y<>0,
        X mod Y<>0,
tt(X,L).
        tt(X,L).</vip>
 
</vip>


=== if-then-else (code) ===
=== if-then-else (code) ===
Line 115: Line 123:


<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
            stdio::write("\n X<=0")
        end if.
 
    pred(X):-
        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
     pred(X,Y)=Z:-
         if X=0 then
             Z="x is zero"
         elseif X>0 then
         elseif X>0 then
             if pred3(Y)=true then
             if pred3(Y) = true then
                 Z="x>0 and pred(Y) is true"
                 Z = "x>0 and pred(Y) is true"
             else
             else
                 Z="x>0 and pred(Y) is false"
                 Z = "x>0 and pred(Y) is false"
             end if  %note, no comma here either
             end if  %note, no comma here either
         else
         else
             Z="x <0"
             Z = "x <0"
         end if.</vip>
         end if.</vip>


=== #if #then #else (directive for conditional compilation) ===
=== #if #then #else (directive for conditional compilation) ===
Line 151: Line 141:


<vip>constants
<vip>constants
     u64_con=1.
     u64_con = 1.
     int_con=2.
     int_con = 2.
     real_con=3.
     real_con = 3.


     compile_big_con=u64_con. %change this and then recompile.
     compile_big_con = u64_con. %change this and then recompile.


#if compile_big_con=u64_con #then
#if compile_big_con = u64_con #then
     predicates
     predicates
         pred:()->unsigned64.
         pred : () -> unsigned64.
     clauses
     clauses
         pred()=U64:-
         pred() = U64 :-
             U64=78766.
             U64 = 78766.


#elseif compile_big_con=int_con #then
#elseif compile_big_con = int_con #then
     predicates
     predicates
         pred:()->integer.
         pred : () -> integer.
     clauses
     clauses
         pred()=Int:-
         pred() = Int :-
             Int=20.
             Int = 20.


#else
#else
     predicates
     predicates
         pred:(real [out]).
         pred : (real [out]).
     clauses
     clauses
         pred(0.766).
         pred(0.766).
Line 179: Line 169:
#endif</vip>
#endif</vip>


'''Note'''<br>
'''Note'''
Code construct uses    <vp>if  - then</vp>,  <vp>elseif  - then</vp>,  <vp>else</vp>,  <vp>end if</vp> <br>
Code construct uses    <vp>if  - then</vp>,  <vp>elseif  - then</vp>,  <vp>else</vp>,  <vp>end if</vp>
compiler directive uses <vp>#if - #then</vp>, <vp>#elseif - #then</vp>, <vp>#else</vp>, <vp>#endif</vp>
compiler directive uses <vp>#if - #then</vp>, <vp>#elseif - #then</vp>, <vp>#else</vp>, <vp>#endif</vp>
<br>(just the "end if" is "different")
(just the "end if" is "different")


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


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


Line 194: Line 183:


<vip>clauses
<vip>clauses
     pred_all():-
     pred_all() :-
         try
         try
             call_pred_that_might_crash(0)
             call_pred_that_might_crash(0)
Line 204: Line 193:


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():-
     always_call_this_anyway() :-
         vpiCommonDialogs::note("finally reached").</vip>
         vpiCommonDialogs::note("finally reached").</vip>


Line 220: Line 209:


<vip>clauses
<vip>clauses
     pred_some():-
     pred_some() :-
         try
         try
             call_pred_that_might_crash(0)
             call_pred_that_might_crash(0)
Line 232: Line 221:


<vip>clauses
<vip>clauses
     pred_some():-
     pred_some() :-
         try
         try
             call_pred_that_might_crash(0)
             call_pred_that_might_crash(0)
Line 242: Line 231:


<vip>clauses
<vip>clauses
     pred_illegal():-
     pred_illegal() :-
         try
         try
             call_pred_that_might_crash(0)
             call_pred_that_might_crash(0)
         end try.</vip>
         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>


=== 64 bit numbers ===
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 ===
=== Polymorphic Domains ===
See [http://wiki.visual-prolog.com/index.php?title=Objects_and_Polymorphism Objects and Polymorphism]<br>


See {{lang|Objects and Polymorphism|Objects and Polymorphism}}


First, check out the definitions - '''core::tuple'''. And while you're there, just below, see '''core::predicate''' and '''core::function'''<br>
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:


The domains in class '''list::''' are polymorphic, but you can define your own polymorphic domains. Here are some examples:
<vip>domains
<vip>domains
poly_dom{A,B}=poly_def(A,B).
    poly_dom{A,B} = poly_def(A,B).</vip>
</vip>
 
When you use it in your code, A and B can be any other domain.<br>
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.
The domain name is '''poly_dom{A,B}''', and you reference it you must use its whole name (not just '''poly_dom''') e.g. <br>
 
<vip>
<vip>domains
domains
    joe{A,B} = poly_dom{A,B}*.
joe{A,B}=poly_dom{A,B}*.
/* the next two lines are illegal
/* the next two lines are illegal
poly_dom{A,B}=poly_def(A,B)*.
    poly_dom{A,B} = poly_def(A,B)*.
poly_dom{A,A}=poly_def(A,A).
    poly_dom{A,A} = poly_def(A,A).
*/
*/
fred{A,B}=fred(poly_dom{A,B},integer).
    fred{A,B} = fred(poly_dom{A,B},integer).


maybe_silly_dom{A,B}=silly2(A,B);
    maybe_silly_dom{A,B} =
silly(A);
        silly2(A,B);
pd(poly_dom{A,B});
        silly(A);
poly_dom(A,B);%IS NOT THE SAME POLY_DOM!! (notice no braces)
        pd(poly_dom{A,B});
s(string).
        poly_dom(A,B);%IS NOT THE SAME POLY_DOM!! (notice no braces)
        s(string).
another{A}=integer;
 
string;
    another{A} =
a(A).
        i(integer);
        s(string);
        a(A);
        self(another({A}).


facts
facts
zz_poly_dom:poly_dom{integer,integer}:=erroneous.
    zz_poly_dom:poly_dom{integer,integer} := erroneous.


class predicates
class predicates
p_morphic_test:().  
    p_morphic_test : ().
clauses
clauses
p_morphic_test():-
    p_morphic_test() :-
zz_poly_dom:=poly_def(1,5),
        zz_poly_dom := poly_def(1,5),
call_pd(zz_poly_dom),
        call_pd(zz_poly_dom),
fail.
        fail.
p_morphic_test():-
    p_morphic_test() :-
PD=poly_def(1,["an example","or two"]),
        PD = poly_def(1,["an example","or two"]),
call_pd(PD),
        call_pd(PD),
fail.
        fail.
p_morphic_test():-
    p_morphic_test() :-
Q= [poly_def(X, Y) || X= std::fromTo(1, 4),
        Q = [poly_def(X, Y) || X = std::fromTo(1, 4), Y = std::fromTo(1, 5)],
Y= std::fromTo(1, 5)],
        stdio::write("\n",Q),
stdio::write("\n",Q),
        fail.
fail.
    p_morphic_test().
p_morphic_test().


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


=== Properties ===
=== Properties ===
Line 324: Line 371:
<vip>interface fred
<vip>interface fred
     domains
     domains
         complete_dom=is_complete;
         complete_dom = is_complete;
                not_complete.
                    not_complete.
     properties
     properties
         prop_complete : complete_dom.
         prop_complete : complete_dom.
end interface fred</vip>
end interface fred</vip>


In fred.pro:
In '''fred.pro''':


<vip>facts
<vip>
     zz_complete:complete_dom:=erroneous.
implement fred
facts
     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</vip>
     prop_complete(COMPLETE) :- zz_complete := COMPLETE. %set</vip>




Line 345: Line 394:
     open fred
     open fred
clauses
clauses
     pred():-
     pred() :-
         Fred=fred::new(),
         Fred = fred::new(),
         Fred:prop_complete:=is_complete,% to set the value
         Fred:prop_complete := is_complete,% to set the value
         Value=Fred:prop_complete,!. %get</vip>
         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>


=== Comparators and compare ===
<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>
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,!.
 
</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>
=== list::isMemberBy example using Comparator===
 
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 ===
=== Anonymous predicates ===


''(under development)''
See [[Language Reference/Terms/Anonymous Predicates|Anonymous Predicates]]
See [http://wiki.visual-prolog.com/index.php?title=Language_Reference/Terms/Anonymous_Predicates Anonymous_Predicates]


'''Examples'''
'''Examples'''
Line 362: Line 595:
<vip>clauses
<vip>clauses
     run() :-
     run() :-
         Anon={()=9},
         Anon = {() = 9},
         K=Anon().
         K = Anon().
         %results in K=9
         %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() :-
     run() :-
        Anon={=88},
         Anon = {
        K=Anon().
             (A,B) = C :-
        %results in K=88.
             R = math::random(7),
    run():-
             C = A+B+R,
        Anon={(A,B)=A+B},
             stdio::wRite("RRRR = ",R)
        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).
         K = Anon(4,8).
         %results in K=12 + a random number <7
         %results in K = 12 + a random number <7


     run():-
     run() :-
         Anon={=f_abc(3)},
         Anon = { = f_abc(3)},
         K=Anon(),
         K = Anon(),
         stdio::write("\nI={=f_abc(3)} gives ",K),
         stdio::write("\nI = { = f_abc(3)} gives ",K),
         fail.
         fail.
     run().</vip>
     run().</vip>


=== Threads ===
=== Threads ===
Line 396: Line 628:


<vip>clauses
<vip>clauses
     pred():-
     pred() :-
         _=thread::start(fred).
         _ = thread::start(fred).


predicates
predicates
     fred:().
     fred : ().
clauses
clauses
     fred():-.....</vip>
     fred() :- .....</vip>


fred can have no arguments, so no argument brackets are allowed:
fred can have no arguments, so no argument brackets are allowed:
<vip>
    _=thread::start(fred())</vip>


is illegal. But the thread can access data prepared before it is started.
<vip>    _ = thread::start(fred())</vip>
 
is illegal.  
 
Using [[Language Reference/Terms/Anonymous Predicates|Anonymous Predicates]] is rather simple to pass arguments to thread:


<vip>facts
<vip>clauses
    zz_int:integer:=erroneous.
     pred(X) :-
clauses
         _ = thread::start( { :- fred(X) } ).
     pred():-
        zz_int:=88,
         _=thread::start(fred).


predicates
predicates
     fred:().
     fred : (integer K).
clauses
clauses
     fred():-
     fred(K) :-
        K=zz_int,
         ...</vip>
         ...</vip>
[[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) :-
        ...