Difference between revisions of "VIP7 Construct examples"
m (formatting) |
m (link) |
||
(41 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. | ||
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 | '''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> | ||
Fact variables are great for counting e.g. | |||
<vip>predicates | <vip>predicates | ||
how_many : () -> integer Count. | |||
clauses | clauses | ||
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 | ||
end foreach. | |||
pred() | |||
clauses | |||
pred() :- | |||
stdio::write("\n There are ", how_many(), " items").</vip> | |||
=== Lists - findall and list comprehension === | === Lists - findall and list comprehension === | ||
See [ | See [[Lists and Recursion]] | ||
<vp>findall()</vp> has been | <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() :- | |||
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).</vip> | |||
=== if-then-else (code) === | === if-then-else (code) === | ||
Line 99: | Line 123: | ||
<vip>clauses | <vip>clauses | ||
pred(X,Y) = Z :- | |||
if X = 0 then | |||
Z = "x is zero" | |||
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 135: | 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 163: | Line 169: | ||
#endif</vip> | #endif</vip> | ||
'''Note''' | '''Note''' | ||
Code construct uses <vp>if - then</vp>, <vp>elseif - then</vp>, <vp>else</vp>, <vp>end if</vp | 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> | ||
(just the "end if" is "different") | |||
=== Trap and try/catch/finally === | === Trap and try/catch/finally === | ||
See [ | See [[Language Reference/Terms/Try-catch-finally|Try-catch-finally]] | ||
Note, in | Note, in [[Language Reference/Built-in entities/Predicates|Built-in entities/Predicates]] | ||
[ | |||
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 178: | 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 188: | 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 204: | 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 216: | 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 226: | 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> | |||
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 === | ||
Line 243: | Line 371: | ||
<vip>interface fred | <vip>interface fred | ||
domains | domains | ||
complete_dom=is_complete; | complete_dom = is_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 264: | 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> | |||
<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 === | ||
See [[Language Reference/Terms/Anonymous Predicates|Anonymous Predicates]] | |||
See [ | |||
'''Examples''' | '''Examples''' | ||
Line 281: | 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 = { | |||
(A,B) = C :- | |||
R = math::random(7), | |||
C = A+B+R, | |||
stdio::wRite("RRRR = ",R) | |||
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 315: | 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: | ||
is illegal. | <vip> _ = thread::start(fred())</vip> | ||
is illegal. | |||
Using [[Language Reference/Terms/Anonymous Predicates|Anonymous Predicates]] is rather simple to pass arguments to thread: | |||
<vip> | <vip>clauses | ||
pred(X) :- | |||
clauses | _ = thread::start( { :- fred(X) } ). | ||
pred():- | |||
_=thread::start(fred). | |||
predicates | predicates | ||
fred:(). | fred : (integer K). | ||
clauses | clauses | ||
fred():- | fred(K) :- | ||
...</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
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
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) :- ...