Difference between revisions of "VIP7 Construct examples"

From wiki.visual-prolog.com

m (TRAP AND TRY/CATCH/FINALLY: add link)
m (link)
 
(46 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 (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
+
#else
predicates
+
    predicates
pred:()->unsigned64.
+
        pred : (real [out]).
clauses
+
    clauses
pred()=U64:-
+
        pred(0.766).
U64=78766.
 
  
#elseif compile_big_con=int_con #then
+
#endif</vip>
predicates
 
pred:()->integer.
 
clauses
 
pred()=Int:-
 
Int=20.
 
  
#else
+
'''Note'''
predicates
+
Code construct uses    <vp>if  - then</vp>,  <vp>elseif  - then</vp>,  <vp>else</vp>,  <vp>end if</vp>
pred:(real [out]).
+
compiler directive uses <vp>#if - #then</vp>, <vp>#elseif - #then</vp>, <vp>#else</vp>, <vp>#endif</vp>
clauses
+
(just the "end if" is "different")
pred(0.766).
 
  
#endif
+
=== Trap and try/catch/finally ===
</vip>
 
'''Note'''<br>
 
Code construct uses    '''if  - then''',  '''elseif  - then''',  '''else''',  '''end if''' <br>
 
compiler directive uses '''#if - #then''', '''#elseif - #then''', '''#else''', '''#endif'''
 
<br>(just the "end if" is "different")
 
  
===TRAP AND TRY/CATCH/FINALLY ===
+
See [[Language Reference/Terms/Try-catch-finally|Try-catch-finally]]
See [http://wiki.visual-prolog.com/index.php?title=Language_Reference/Terms/Try-catch-finally Try-catch-finally]<br>
+
Note, in [[Language Reference/Built-in entities/Predicates|Built-in entities/Predicates]]
Note, in  
+
suggests using <vp>try-end try</vp> instead of <vp>trap(_,_,_)</vp>
[http://wiki.visual-prolog.com/index.php?title=Language_Reference/Built-in_entities/Predicates Built-in entities/Predicates]<br>
 
suggests using '''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]]
  
===ANONYMOUS PREDICATES===
 
''(under development)''<br>
 
See [http://wiki.visual-prolog.com/index.php?title=Language_Reference/Terms/Anonymous_Predicates Anonymous_Predicates] <br>
 
 
'''Examples'''
 
'''Examples'''
<vip>
 
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():-
+
<vip>clauses
Anon={=f_abc(3)},
+
    run() :-
K=Anon(),
+
        Anon = {() = 9},
stdio::write("\nI={=f_abc(3)} gives ",K),  
+
        K = Anon().
fail.
+
        %results in K = 9
run().
+
    run() :-
</vip>
+
        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>
 +
 
 +
[[Category:Examples]]

Latest revision as of 11: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) :-
        ...