VIP7 Construct examples

From wiki.visual-prolog.com

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

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.

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,
        ...