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:=0, some_nondeterm_fact_or_pred(), zz_int:=zz_int+1, fail. how_many()=zz_int. clauses pred():- stdio::write("\n There are ",how_many()," items").
Lists - findall and list comprehension
See Lists and Recursion
findall() has been depricated, 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:
unsigned64_struct = unsigned64(unsigned Low, unsigned High). integer64_struct = integer64(unsigned Low, integer High).
So, for example, in VIP7.1:
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:
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 = -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
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.
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
(under development) 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. But the thread can access data prepared before it is started.
facts zz_int:integer:=erroneous. clauses pred():- zz_int:=88, _=thread::start(fred). predicates fred:(). clauses fred():- K=zz_int, ...