VIP7 Construct examples

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.

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

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

predicates pred : (real [out]). clauses pred(0.766).
 * 1) else


 * 1) endif

Note Code construct uses    if  - then,  elseif  - then,  else,  end if compiler directive uses #if - #then, #elseif - #then, #else, #endif</vp> (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</vp> instead of trap(_,_,_)</vp>

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</vp> or finally</vp>

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{}</vp>. And while you're there, just below, see core::predicate{}</vp> and core::function{}</vp>, then followed by comparator{A}</vp> and list{A}</vp>.

The domains in class list::</vp> 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}</vp>, and you reference it you must use its whole name (not just poly_dom</vp>) 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</vp>'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</vp> 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</vp>. <vp>core::predicate</vp> 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) :- ...