Upload
vermuz
View
214
Download
0
Embed Size (px)
Citation preview
7/31/2019 Prova 3.0 User Guide - May 2010
1/94
ProvaRuleLanguageVersion3.0
UsersGuide
Prova is an economic and efficient open source rule
language for creating distributed collaborating agents.
Running in Java runtime, it combines Prolog style logic
inference with extensions for Java scripting, concurrent
and scalable reactive messaging, workflows and event
processingsuitableforEnterpriseServiceBusdeployment.
AlexKozlenkov
May2010
7/31/2019 Prova 3.0 User Guide - May 2010
2/94
7/31/2019 Prova 3.0 User Guide - May 2010
3/94
1. General language features .............................................................. 1
1.1. Basiclanguageelements.................................................................................................1
1.1.1. Simple(atomic)terms.................................................................................................2
1.1.2. Variables......................................................................................................................2
1.1.3.Constants
....................................................................................................................
2
1.1.4. Compoundterms(lists)...............................................................................................3
1.1.5. Facts............................................................................................................................3
1.1.6. Rules............................................................................................................................3
1.2. RunningProvascriptsfromcommandline.....................................................................3
1.3. RunningProvafromJava................................................................................................4
1.3.1. PassingJavaobjectstotheinitializationrulebase......................................................5
1.3.2. PassingJavaobjectstotheaddedrulebasefragment................................................7
1.3.3.Submitting
goals
and
obtaining
solutions
...................................................................
7
1.3.4. Sendingmessagestotherunningrulebase................................................................8
1.3.5. ProvaServiceasimplerwaytoembedProvaagents...............................................8
1.3.6. RunningProvainsideanOSGicontainer..................................................................11
1.3.7. ProvaagentcontractandESBadaptor.....................................................................12
1.4. CallingJavafromProvarulebases.................................................................................13
1.4.1. UsingJavatypesandclassesforProvavariables......................................................13
1.4.2. CreatingJavaobjectsbycallingtheirconstructors...................................................15
1.4.3.Passing
Prova
lists
as
arguments
to
constructors
.....................................................
15
1.4.4. Invokingstaticmethods............................................................................................15
1.4.5. Accessingpublicstaticandinstancefields...............................................................15
1.4.6. UsingspecialbuiltinsthattakeadvantageofcommonJavaclasses.......................15
1.5. Expressions....................................................................................................................15
1.6. Globalconstants............................................................................................................16
1.7. Provamapsfordefiningslottedterms.........................................................................16
1.8. Metadataannotations..................................................................................................17
1.9.
Guardsin
Prova
.............................................................................................................
18
1.10. Workflowsandbusinessprocesses..............................................................................19
1.10.1. Simplegateways...................................................................................................19
1.10.2. Eventdrivengateways(edBPM)...........................................................................21
1.10.3. Predicategateways...............................................................................................23
1.11. Functionalprogrammingextensions............................................................................25
1.11.1. Representingfunctions.........................................................................................25
1.11.2. Functionalcomposition.........................................................................................26
1.11.3.
Lambdafunctions
..................................................................................................
26
1.11.4. Simplefunctionalcomposition.............................................................................27
7/31/2019 Prova 3.0 User Guide - May 2010
4/94
2
1.11.5. Monadicfunctionalcomposition..........................................................................28
1.12. Builtinsreference..........................................................................................................28
2. Reactive messaging ..................................................................... 47
2.1. Designprinciples...........................................................................................................47
2.2.
Sendingmessages
.........................................................................................................
47
2.2.1. Positionbasedarguments........................................................................................47
2.2.2. SynchronizedmessagesendingwithsendMsgSync.................................................50
2.3. Usingreactionrulesforreceivingmessages.................................................................51
2.3.1. Globalreactionrules.................................................................................................51
2.3.2. Inlinereactionrules..................................................................................................52
2.3.3. Controllingthemessagereactionmultiplicity..........................................................52
2.3.4. Explicitterminationofinlinereactions.....................................................................53
2.4.
Guardsin
message
processing
......................................................................................
54
2.5. Concurrentreactivemessaging....................................................................................54
2.6. Annotationsformessagereceiving...............................................................................58
2.7. ReactivemessagingforJavaSwing...............................................................................59
3. Event processing ......................................................................... 60
3.1. Eventprocessingusingreactiongroups.......................................................................60
3.1.1. Whiteboxorworkfloweventprocessing.................................................................61
3.2. Structureofreactiongroups.........................................................................................61
3.3.
Annotationsfor
reaction
groups
...................................................................................
63
3.4. Lifecycleofreactiongroupinstances............................................................................74
3.5. ContextvariableswithequalityandWHEREconstraintsinANDgroups.....................77
3.6. Dynamiceventchannels...............................................................................................80
3.7. EPTSLanguageWorkingGroup.....................................................................................82
3.7.1. Flowerdeliveryexample...........................................................................................82
3.8. Glossary.........................................................................................................................89
7/31/2019 Prova 3.0 User Guide - May 2010
5/94
Pro
1.Ge1.1.
Alth
Reader
givena
The
simples
new sy
refactor
increme
languag
quality
The
Att
arulelangu
nerallaBasiclanoughthero
willneed to
ditionalse
syntactic si
yntaxiseasi
ntactic refin
ing.The ide
ntally,with
es that fost
xecutables
followingdi
hetoplevel,
age3.0
guagefuageelem
otsofProva
keepano
anticsand
mplicityof
iertocompr
ements ea
alhere is t
minimalcha
erquick ex
stems.
agramcapt
Provaoffer
aturesents
lieinlogic
enminda
andomuch
he languag
ehendand
ily availabl
atofadev
ngestothe
erimentatio
resthemai
threebasic
UsersG
rogrammin
daccept th
morethan
isentirely
ostimport
via linear
eloper thin
existingcod
n and yet,
nlanguagee
syntacticst
uide
g(LP),thesi
at syntactic
inatypicalP
intentional
antly,easier
code chan
ingabouta
e.Thelangu
in the best
lements.
ructuresfor
milaritycan
structures
rologlikela
andmotiva
toscaleup
es as opp
new functi
ageisthus
examples, li
puttingtog
bedeceptiv
amiliar fro
nguage.
tedby the i
andbackdo
sed to co
nalityand
arcloserto
ike Ruby, yi
theraruleb
ay2010
e,sothe
LP,are
dea that
wn,with
plicated
adding it
scripting
ld high
ase:
7/31/2019 Prova 3.0 User Guide - May 2010
6/94
Provarulelanguage3.0 UsersGuide May2010
2
rules,
facts(ruleswithnobody),
goals(ruleswithnohead).
Thesearebuiltattheelementallevelfrom
atomicterms,
compoundterms
(lists).
Letustalkabouttheminabottomupfashion.
1.1.1.Simple(atomic)termsProva includes two types of simple terms: constants and variables. Internally, they are Java
interfacesProvaConstantandProvaVariable,respectively.
1.1.2.VariablesProvavariablesareessentiallyhollowpointersthatareyettobegivensomevalueassignment.
Oncethevalue isassigned,thevariablebecomesaconstantterm,that isadatawrapperarounda
Javaobject.Onceaconstantisassigned,inatypicallogicandfunctionalprogrammingway,itcannot
beassigned
some
other
data.
However,
ifafailure
(inability
to
prove
anew
sub
goal)
is
detected
during the goal evaluation, backtracking may result in alterantive branching, and therefore,
alternativeassignmentstovariables.Assignmentofvaluestovariablesultimately isthemainpoint
ofrunningaProvarulebase,i.e.,providinganswerstoquestions(goals)thatarebeingasked.
AsopposedtotypicalPrologsystems,variablescanbetyped(seethediscussion inCallingJava
from Prova rulebases). Previous versions of Prova also allowed variables tobe typedusingOWL
ontologies.ThisfeatureisnotavailableinProva3.0butwillreturninthenextversion.
Syntactically,ascommon inProlog,variablesarerepresentedbytokensstartingwithacapital
letter, in the case of typed variables, prefixed by fully qualified package and class name of the
corresponding Java class. It is also possible to use anonymous variables that begin with the
underscorecharacter.SomeexamplesofProvavariablesfollow.
APayloadInteger.Icom.betfair.prova.domain.Market.M_
1.1.3.ConstantsConstantsmayincludenumericdatausingtheJavasyntax,stringsinsingleordoublequotes,as
well as fullyqualified staticor instance fields in Javaobjects. Singleword strings thatbeginwith
lowercaseletterareforallpurposesthesameassuchstringsinquotes.12300L
3.0e
9
test'test'"test"
It is important to understand that during the execution of a Prova rulebase, variables get
assigned values essentially becoming constants. In this case, however, these variables are
syntacticallyrepresentedasvariables,yetforallpurposes,behavelikeconstants.Forexample,going
slightlybeyond the scopeof thissubsection, thisassignmentsets thevariable toaconstant,and
subsequentreassignmentofthesamevariablefails.I=2,I='cannotassign'
Specialglobalconstantshavenamesstartingwith'$'asbelow.
$Count.addAndGet(Delta)
7/31/2019 Prova 3.0 User Guide - May 2010
7/94
Provarulelanguage3.0 UsersGuide May2010
3
1.1.4.Compoundterms(lists)Compoundtermsare inProvarepresentedasgenericProva lists.This lendsitselfwelltoagent
programmingasanyinformationcanbeeasilydistributedwithagentssendingeachotherProvalists.
Critically, and uniquely different from typical LP languages, Prova keeps lists in arrays instead of
recursivelists.
Listsare
represented
in
astandard
Prolog
way
as
[Head|Rest]
Here Head is one or more (commaseparated) elements that are the list's starting (prefix)
elements. The Rest is the list tail, thatmost often isjust a variable thatwillmatch against the
remainderofthelist.Theverticalbaristhenthesameastheconsoperatorinfunctionallanguages.
Listsareaninvaluabletoolforpatternmatching,sothatwecansay,wewantthoseelementstobe
thereinthelistandunification,whichisthecoreoperationinProva,willmatchthelistsandassign
valuestofreevariablesasappropriate.
1.1.5.FactsAProva fact is essentially a relation tuple (a record)with its elementsbeing any term, be it
constant,variable,
or
a(possibly
recursive)
list.
This
is
different
from
standard
Prolog,
where
facts
normallycannothavevariables.Moreover, factscanhaveembedded Javaobjects,orevenglobal
constants.Factshavethefollowingformat.predicate(arg1,...,argn).
Itisoftenthecasethattherearemorethanonefactforagivenpredicatesymbol.alert_destination(no_bids,store2).alert_destination(no_bids,store_manager2).
1.1.6.RulesProvarulestypicallyareHornrulesthatare firstorderdisjunctionsof literalswithexactlyone
positiveliteral.Inlogics,suchHornrulesareknownasdefiniteclauses.Thewordtypicallyhighlights
the
fact
that
in
Prova,
global
reaction
rules
look
exactly
like
Prova
rules
(with
head
literal
for
predicate symbol rcvMsg) but their semantics aremore aligned with reactive rules rather than
derivationrules.
RulesarewritteninthestandardProloglikeway.Where':'ispronouncedasIF.head_literal(args_h): body_literal1(args_1), ..., body_literaln(args_n).
1.2. RunningProvascriptsfromcommandlineThenewProvamain()ishostedbytheProvaCommunicatorImplclass.Currently,itrequiresthe
followingcommandlinearguments:
1. agentname,2. password(unusedfornow),3. startingrulebase(withpossiblyincludedgoalsthatareimmediatelyrunsynchronously).
Optionally,thetimeoutfortheagentcouldbespecifiedafterthatwitht.
Specifying theoption t 1 allows the agent to run indefinitely, accepting goals asmessages and
respondingbyotheractions.Ifthetimeoutparameterisnotprovided,theengineexecutesallgoals
in the starting rulebaseand then ifno internalmessageswere sent (as is the casewitha typical
rulebase thathasnomessage sendingor receiving), it exits to the command shell.Otherwise, it
looksforonesecondlongperiodofinactivitywhennomessagesaredetectedandthenexitstothe
commandshell.
ThebinaryProvadistributionallowsrunningthenewProvainterpreterfromcommandlineusing
prova3.bat[t]arg0arg1...argN
7/31/2019 Prova 3.0 User Guide - May 2010
8/94
Provarulelanguage3.0 UsersGuide May2010
4
The list of commandline arguments is passed to the starting rulebase as global constants:
$0,$1..,$N.
Hereisanexampleoftheargumentspassedtotherunner:agentpasswordtest001_args.provaanticoagulant
The
following
rulebase
test001_args.prova
then
prints
one
solution
Parent=molecular_function.
is_a("anticoagulant","molecular_function").
%Rules(howtoderivenewknowledge)parent(X,Y):%XisparentofYIFYisa(kindof)X is_a(Y,X).parent(X,Y):%XisparentofYIFXhasaY has_a(X,Y).
%Goal(whattodo/whattoderive)%WhoisParentof"anticoagulant"?:solve(parent(Parent,$0)).
1.3. RunningProvafromJavaProva iswritten in Java but clearly, there needs to be away for a generic Java program to
somehow 'initialise'aProvaagentandinteractwith it.TheProvaagentthatservesthispurpose is
ProvaCommunicatorImpl, an implementation of the interface ProvaCommunicator. In the test
directory for the new Prova, test.ws.prova.test2,not alltests are created equal. Some work on
primitiveconstructs,explicitlycreatingvariablesorrules fromscratch.Wedonotwanttodo that
here so let's create a ProvaCommunicator instance and give it a spin. When you create a
ProvaCommunicator,there isonemainquestionyouneedtoanswer,whatrulebasetheagentwill
initially run? Let's look at the test capture_enum() in test.ws.prova.test2.ProvaBuiltins1.java
reproducedbelow:staticfinalStringkAgent="prova";
staticfinalStringkPort=null;
@Testpublicvoidcapture_enum(){ finalStringrulebase="rules/reloaded/test017.prova"; finalint[]numSolutions=newint[]{2}; ProvaCommunicatorprova=new
ProvaCommunicatorImpl(kAgent,kPort,rulebase,ProvaCommunicatorImpl.SYNC); Listsolutions=prova.getInitializationSolutions(); org.junit.Assert.assertEquals(solutions.size(),1); org.junit.Assert.assertEquals(solutions.get(0).length,numSolutions[0]);
org.junit.Assert.assertTrue(solutions.get(0)[0].getNv("Groups")
instanceof
ProvaList);
}
This is the simplestway to callProva from Java.We createaProvaCommunicatorImpl,passing it
(apart from theuniqueagentnameandport,discussedelsewhere), the rulebase tobe consulted
and indicating that theagentwillbe run ina synchronousmode.At the timeofwriting, this last
parameter is in fact, ignored. If the initial rulebase has any goals, they are run right in the
ProvaCommunicatorImpl constructor, making their results available when the client calls
ProvaCommunicator.getInititalizationSolutions().ThismethodreturnsaList,which
isalistofsolutionarrays,oneeachforeachgoalinsidetheinitialisationrulebase.Sointhecurrent
example,wehaveonegoalandtwosolutionsforthatgoal.EachProvaSolutioncontainsname/value
pairscorrespondingtovariables'binding.Thecorrespondingrulebaseisshownbelow.:solve(test017(Groups)).
7/31/2019 Prova 3.0 User Guide - May 2010
9/94
Provarulelanguage3.0 UsersGuide May2010
5
test017(Groups): Text="Adoodleisadoddle", %nondeterministicallyenumerateregularexpressiongroups capture_enum([Text,"(d?)(dl)"],Groups).
1.3.1.PassingJavaobjectstotheinitializationrulebase
JavaobjectscanbepassedtotheProvaengineinavarietyofways.Inparticular,youcanembed
Java objects directly into the initialization rulebase, i.e., the rulebase consulted when the
ProvaCommunicator is constructed, creating a Prova engine instance. The following code from
ProvaBuiltins1Test.javademonstrates. @Test publicvoidread_enum(){ finalStringrulebase="rules/reloaded/read_enum.prova"; finalint[]numSolutions=newint[]{5};
Mapglobals=newHashMap(); globals.put("$File",rulebase);
ProvaCommunicator
prova
=new
ProvaCommunicatorImpl(kAgent,kPort,rulebase,ProvaCommunicatorImpl.SYNC,globals); Listsolutions=prova.getInitializationSolutions();
org.junit.Assert.assertEquals(1,solutions.size()); org.junit.Assert.assertEquals(numSolutions[0],solutions.get(0).length); }
Thiscodepassesamapglobalswithnamedconstants (inthisexample,$File)totheconsulted
rulebaseread_enum.provashownbelow.:solve(test_read_enum_1(Line)).
test_read_enum_1(Line):
fopen($File,Reader),
read_enum(Reader,Line).
Therulebaseopensthefilegiventhesuppliedfilename.AnyJavaobjectscanbepassedtothe
rulebaseinthisway.Forexample,youcandirectlyembedarbitraryJavaobjectsintoProvafactslike
this.customer(1234,$c1).
Dealingwithexceptions
Ifexceptionsoccurduringthe initialization,theenginewrapsthem inaRuntimeExceptionwith
theappropriateunderlyingexceptionreportedasitscause.Thefollowingtestshowsafailuredueto
non
existence
of
the
consulted
rulebase.
@Testpublicvoidinitialization_from_nowhere(){ finalStringrulebase="rules/reloaded/NOSUCHFILE.prova";
try{ comm=newProvaCommunicatorImpl(kAgent,kPort,rulebase,ProvaCommunicatorImpl.SYNC); }catch(Exceptione){ finalStringlocalizedMessage=e.getCause().getLocalizedMessage(); org.junit.Assert.assertEquals( "Cannotreadfromrules/reloaded/NOSUCHFILE.prova", localizedMessage);
}
}
7/31/2019 Prova 3.0 User Guide - May 2010
10/94
Provarulelanguage3.0 UsersGuide May2010
6
Ifthereareparsingerrors,thewrappedexceptionisaProvaParsingException.Thisexceptionhas
twofieldsthatprovidefurther information:srcanderrors, i.e,thefileoriginoftherulebaseanda
collectionofactualparsingerrors.Thiscollectionmaps linesandoffsets in format line:offset toa
textualdescriptionoftheencounteredparsingerrorasreportedbytheparser.Thefollowingcode
fragmentillustrates.
@Testpublicvoidinitialization_with_parsing_errors(){ finalStringrulebase="rules/reloaded/parsing_errors.prova";
try{ comm=newProvaCommunicatorImpl(kAgent,kPort,rulebase,ProvaCommunicatorImpl.SYNC); }catch(Exceptione){ org.junit.Assert.assertTrue(e.getCause()instanceofProvaParsingException); org.junit.Assert.assertEquals( "rules/reloaded/parsing_errors.prova", ((ProvaParsingException)e.getCause()).getSource()); org.junit.Assert.assertEquals(5,((ProvaParsingException)e.getCause()).errors().size());
}
}
Finally, if an exception occurs inside the rulebase, for example, caused by a failedmethod
invocation, the exception is also wrapped in a RuntimeException. The following rulebase
processing_errors.provathrowsaNoSuchMethodException.
:solve(p(X)).
p(X): A=java.util.HashSet(), A.nomethod().Thetestbelowshowshowtodetectthisexception.
@Testpublicvoidinitialization_with_rulebase_errors(){ finalStringrulebase="rules/reloaded/processing_errors.prova";
try{ comm=newProvaCommunicatorImpl(kAgent,kPort,rulebase,ProvaCommunicatorImpl.SYNC); }catch(Exceptione){ finalStringlocalizedMessage=e.getCause().getLocalizedMessage(); org.junit.Assert.assertEquals( "Nosuchaccessiblemethod:nomethod()onobject:java.util.HashSet", localizedMessage); }}
Modifyingtherulesinarunningengine
When a Prova engine instance is active, i.e, the ProvaCommunicator object is successfully
constructed,thelattercanbeusedforaddingandremovingadditionalfactsorrulestotherunning
rulebase.Ifthenewconsultedcodecontainsgoals,thesegoalswillthenbeexecuted.TheexamplebelowshowstheuseoftheProvaCommunicator.consultSyncmethodtoaddanew
fragmenttotherunningrulebase.
StringinputRules="dissemination(Person,public_reports):clearance(Person,low).";BufferedReaderinRules=newBufferedReader(newStringReader(inputRules));
try{
7/31/2019 Prova 3.0 User Guide - May 2010
11/94
Provarulelanguage3.0 UsersGuide May2010
7
comm.consultSync(inRules,"disseminationrules",newObject[]{});}catch(Exceptione){ //TODO:processexceptions}
Themethodtakesthreeparameters:
1. eitheraStringorBufferedReaderwitharulebasefragmentinProva;2. aStringwiththelogicalnamegiventotherulebasefragment;3. anarrayofJavaobjectstoreplaceanyplaceholdersembeddedinthefragment.
Thecallmayraiseexceptionsthattheuserisrequiredtoprocess.
Removingorreplacingthecode
The name of the rulebase fragment can be used later for removing the previously added
fragment.
//Removeallclausesconsultedforthiskeycomm.unconsultSync("disseminationrules");
Thefragmentcanbetheneasilyupdatedbyconsultingitagainwithanewversioninaseparate
step.
1.3.2.PassingJavaobjectstotheaddedrulebasefragmentThesourcecodesubmittedtoconsultSynccancontainplaceholders inthesyntax_0,...,_nthat
thecallwillreplacewiththeJavaobjectssuppliedinthethirdparameterintherulebase.
Stringinput="robot(_0).";BufferedReaderin=newBufferedReader(newStringReader(input));
try{ comm.consultSync(inRules,"robotrules",newObject[]{newRobot("Dave")});}catch(Exceptione){
//
TODO:
process
exceptions
}
Thisisactuallymorepowerfulthanwhatyoucandofromarulebaseconsultedfromanexternal
file during initialization because to embed a Java object in a factwould have required explicitly
constructingaJavaobjectandaddingafactdynamicallyusingassert.
Robot=com.independentrobots.Robot(),assert(robot(Robot))
1.3.3.SubmittinggoalsandobtainingsolutionsIfthefragmentrulebasecontainsclausesformetapredicatesevalorsolve,theyareexecutedas
newgoals.
The
solutions
resulting
from
the
solve
goals
(eval
do
not
produce
any
solutions)
are
returnedinaListinthesamewayitworksforinitializationsolutions.
Stringinput=":solve(dissemination(Person,public_reports)).";BufferedReaderin=newBufferedReader(newStringReader(input));
try{ ListresultSets=comm.consultSync(in,Integer.toString(key++),newObject[]{}); for(ProvaSolution[]resultSet:resultSets){ org.junit.Assert.assertEquals(numSolutions[i++],resultSet.length); }}catch(Exceptione){
//
TODO:
Process
exceptions
}
7/31/2019 Prova 3.0 User Guide - May 2010
12/94
Provarulelanguage3.0 UsersGuide May2010
8
1.3.4.SendingmessagestotherunningrulebaseTherearetwowaystosendamessagetotherunningProvarulebasefromJava.The lowlevel
ProvaCommunicator.addMsgmethodcanbeusedforsendingamessageconstructedfromaProva
termexplicitlybuiltfromthebasicbuildingprimitives,suchasconstantsorlists.Theexamplebelow
demonstrates.
//Send
ahundred
messages
to
the
consulted
Prova
rulebase.
//Processingisdoneconcurrentlyonthreadsbelongingtotheasyncpool.for(inti=0;i
7/31/2019 Prova 3.0 User Guide - May 2010
13/94
Provarulelanguage3.0 UsersGuide May2010
9
*NotethatthisrunsinplainJavanoOSGicontainerisactuallyrequired.**TherunnerimplementsEPServiceforProvaenginestobeabletosendmessagestotherunner,*notjustbetweenthemselves.**@authorAlexKozlenkov
*/
publicclassProvaSimpleServiceimplementsEPService{ staticfinalStringkAgent="prova"; staticfinalStringkPort=null; finalStringsender_rulebase="rules/service/message_passing/sender.prova"; finalStringreceiver_rulebase="rules/service/message_passing/receiver.prova"; privateProvaServiceservice;
publicProvaSimpleService(){ service=newProvaServiceImpl(); service.init(); }
private
void
run()
{
//CreatetwoProvaagentsintheirownengines Stringsender=service.instance("sender",""); Stringreceiver=service.instance("receiver","");
//Consultonerulebaseintoeach service.consult(receiver,receiver_rulebase,"receiver1"); //Makesuretheconsumerhasaccesstoaglobalobjectforcounting AtomicIntegercount=newAtomicInteger(); service.setGlobalConstant(receiver,"$Count",count); service.consult(sender,sender_rulebase,"sender1");
//
Send
a
message
directly
from
this
runner
Mappayload=newHashMap(); payload.put("a",2); //Thisrunnernamesitselfas"runner"agentinthiscall(seethethirdargument). //ThisEPServiceimplementationispassedinthelastargument. //TheservicewillthenregisteranEPServicecallbacksothatagentswillbeableto //sendmessagestothisrunnersettingthedestinationto"runner". service.send("xid","receiver","runner","inform",payload,this);
try{ synchronized(this){ wait(2000); //Verifythatthecounthadbeenincremented
assert(count.get()==2);
} }catch(Exceptione){ } System.out.println("Confirmedthatthemessageshavebeenreceived");
//Bringbothenginesdown:ifwehadnotdonethat,bothagentswouldhavecontinuedindefinitely
service.destroy(); }
/** *ThisisacallbackthatiscalledwhenaProvaengine(seereceiver.prova)sendsamessagetothis
runner */
7/31/2019 Prova 3.0 User Guide - May 2010
14/94
Provarulelanguage3.0 UsersGuide May2010
10
@Override publicvoidsend(Stringxid,Stringdest,Stringagent,Stringverb, Objectpayload,EPServicecallback){ System.out.println("Received"+verb+"from"+agent+":"+payload); }
public
static
void
main(
String[]
args
)
{
newProvaSimpleService().run(); }}Thisrunnercodeusestworulebasesbelow.Thisisa"receiver"agentinrules/service/receiver.prova.:eval(receiver()).
receiver(): rcvMult(XID,Protocol,From,inform,{a>I}), println(["Received",{a>I}]), $Count.incrementAndGet(),
%ThisonlymakessenseifrunfromProvaSimpleService.java
sendMsg(XID,osgi,runner,inform,{a
>I}).
Thisisa"sender"agentinrules/service/sender.prova.:eval(sender()).
sender(): sendMsg(XID,osgi,receiver,inform,{a>1}).
When the runner code is initialized in the ProvaSimpleService constructor, it creates and
initializesaProvaServiceinstance.ItthencreatestwoProvaagentsusingtheProvaService.instance()
methodand thenusesthemethodconsulttoadd theProvarulebases to thoseagents.When the
rulebasesareconsulted,theyruntheirevalgoalswiththesendersendingandthereceiverreceiving
amessage. For the agents to be "visible" to each other, theymust communicate via the "osgi"
protocol(thesecondargumentinsendMsgandrcvMsg).
Using a global object count is only needed in this slightly contrived example:we use it for
incrementingthecountofexpectedmessages(see$Count.incrementAndGet()inreceiver.prova)and
checkingthiscountfromtheJavacode.
Theexample alsodemonstrates thatwe canboth sendmessages to the selected agents and
receivemessagesbackfromtheJavacode.Forthistowork,thekeyistopassachosennameofthe
containing"agent"tothe_ProvaService.send()_method:
service.send("xid","receiver","runner","inform",payload,this);
ProvaService registers the name "runner" against the callback object passed as the last
parameter.Note that the ProvaSimpleService implements the EPService interface, allowing it the
ProvaagentstocallbackontheEPService.send()methodwhentheneedtosendmessagesbackto
thecontainingagent.ObservethesendMsgwithdestination"runner"inreceiver.prova.
sendMsg(XID,osgi,runner,inform,{a>I}).Also,observetheuseofJavaMapforpassingmessagepayloadsbetweenallparties, including
the embedding agent. This improvesperformance and yet allows for considerable flexibility (see
Provamapsandmessagingusingslottedterms).
Thisisatypicaloutputfromrunningthisprogram.ProvaService7faee1dea6e1421dac2e97709ba47196created==========Servicemessagingtest:receiver====================Servicemessagingtest:sender==========Received{a=1}Received{a=2}Receivedinformfromreceiver:{a=1}
Received
inform
from
receiver
:{a=2}
ConfirmedthatthemessageshavebeenreceivedProvaService7faee1dea6e1421dac2e97709ba47196destroyed
7/31/2019 Prova 3.0 User Guide - May 2010
15/94
Provarulelanguage3.0 UsersGuide May2010
11
To summarize, we are able to exchange messages between all parties: the Java code
representinganembeddingagentandtheembeddedProvaagents.Themessagescanflow inany
directionbetweenallpartieswithonlylogicalagentnamesrequiredasdestination.
1.3.6.RunningProvainsideanOSGicontainerProva
3.0
is
packaged
as
an
OSGi
bundle
that
can
expose
aProva
service
and
necessary
domain
classes accessible from other bundles in an OSGi container. We use METAINF/MANIFEST.MF
reproducedbelowfordeclaringthebundledependenciesanddeclaringpackagesandservicesuseful
forotherbundles.ManifestVersion:1.0BundleVersion:3.0.0BundleName:ProvacompactBundleManifestVersion:2BundleDescription:ProvaruleenginecompactBundleSymbolicName:ws.prova.compactBundleRequiredExecutionEnvironment:J2SE1.5ImportPackage:org.osgi.framework;version="1.3.0",
org.apache.commons.collections;version="3.2.1",
org.apache.commons.beanutils;version="1.8.0",org.apache.log4j;version="1.2.15"RequireBundle:com.springsource.org.antlr.runtime;bundleversion="3.1.3"ExportPackage:ws.prova.service;version="3.0.0",ws.prova.api2;version="3.0.0",ws.prova.exchange;version="3.0.0",ws.prova.exchange.impl;version="3.0.0"BundleClassPath:.,target/classes/,rulesBundleActivationPolicy:lazy
Aswecansee,thenumberofdependenciesthatProvareliesonisverysmall.WealsouseSpring
DMcontext
configurations
in
META
INF/spring
to
make
ProvaService
available
to
other
bundles
as
a
service.WhenanOSGitargetplatformstarts,itexposestheProvaServiceasanOSGiservicewithout
ushavingtohaveanydependencyorcouplingintheprojectitselfonOSGiorSpring.
Youcandownloadtheplatformfrom:http://www.prova.ws/downloads/platform.zip.Unzipitto
adirectoryandfromEclipsegotoWindow/Preferences/Plugindevelopment/Targetplatformand
createandchooseanew targetplatformusing thedirectoryyouexpanded theplatformbundles
into.
Check out the Prova Eclpse project from
https://mandarax.svn.sourceforge.net/svnroot/mandarax/prova3/provacompact/trunk and run
mvncleaninstall DskipTestsfromcommandline.RefreshtheprojectinEclipse.
YoucanruntheProvabundleinanOSGicontainerbyfirstcreatinganewrunconfigurationby
goingto
Run/Run
configurations.../OSGi
Framework
including
the
Prova
bundle
from
the
Prova
projectinadditiontoallthebundlesincludedinthe importedplatform.Runningthisconfiguration
willoutputsomethinglikethistotheconsole:osgi>0[StartLevelEventDispatcher]INFO
org.springframework.osgi.extender.internal.activator.ContextLoaderListenerStarting[org.springframework.osgi.extender]bundlev.[1.2.1]
90[StartLevelEventDispatcher]INFOorg.springframework.osgi.extender.internal.support.ExtenderConfigurationNocustomextenderconfigurationdetected;usingdefaults...
99[StartLevelEventDispatcher]INFOorg.springframework.scheduling.timer.TimerTaskExecutorInitializingTimer
185[StartLevelEventDispatcher]INFO
org.springframework.osgi.extender.support.DefaultOsgiApplicationContextCreatorDiscovered
configurations{osgibundle:/METAINF/spring/*.xml}inbundle[Provacompact(ws.prova.compact)]
7/31/2019 Prova 3.0 User Guide - May 2010
16/94
Provarulelanguage3.0 UsersGuide May2010
12
357[SpringOsgiExtenderThread1]INFOorg.springframework.osgi.context.support.OsgiBundleXmlApplicationContextRefreshingOsgiBundleXmlApplicationContext(bundle=ws.prova.compact,config=osgibundle:/METAINF/spring/*.xml):startupdate[ThuApr2913:54:59BST2010];rootofcontexthierarchy
358[SpringOsgiExtenderThread1]INFOorg.springframework.osgi.context.support.OsgiBundleXmlApplicationContextApplicationContextservice
alreadyunpublished
426[SpringOsgiExtenderThread1]INFOorg.springframework.beans.factory.xml.XmlBeanDefinitionReaderLoadingXMLbeandefinitionsfromURL[bundleentry://59.fwk1384828782/METAINF/spring/modulecontext.xml]
755[SpringOsgiExtenderThread1]INFOorg.springframework.beans.factory.xml.XmlBeanDefinitionReaderLoadingXMLbeandefinitionsfromURL[bundleentry://59.fwk1384828782/METAINF/spring/moduleosgicontext.xml]
907[SpringOsgiExtenderThread1]INFOorg.springframework.osgi.extender.internal.dependencies.startup.DependencyWaiterApplicationContextExecutorNooutstandingOSGiservicedependencies,completinginitializationforOsgiBundleXmlApplicationContext(bundle=ws.prova.compact,config=osgibundle:/METAINF/spring/*.xml)
911[SpringOsgiExtenderThread2]INFOorg.springframework.beans.factory.support.DefaultListableBeanFactoryPreinstantiatingsingletonsinorg.springframework.beans.factory.support.DefaultListableBeanFactory@57c8b24d:
defining
beans
[provaService,org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean#0];rootoffactoryhierarchy
ProvaService090128f4d886400aa63185088bdd08e0created996[SpringOsgiExtenderThread2]INFO
org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBeanPublishingserviceunderclasses[{ws.prova.service.ProvaService}]
999[SpringOsgiExtenderThread2]INFOorg.springframework.osgi.context.support.OsgiBundleXmlApplicationContextPublishingapplicationcontextasOSGiservicewithproperties{org.springframework.context.service.name=ws.prova.compact,BundleSymbolicName=ws.prova.compact,BundleVersion=3.0.0}
1006[SpringOsgiExtenderThread2]INFO
org.springframework.osgi.extender.internal.activator.ContextLoaderListener
Application
context
successfullyrefreshed(OsgiBundleXmlApplicationContext(bundle=ws.prova.compact,config=osgibundle:/METAINF/spring/*.xml))
ThisconfirmsthattheProvabundlestartedsuccessfully.
1.3.7.ProvaagentcontractandESBadaptorThewaytostartaProvaenginefromJavadescribedinthepreviousSectiondoesnotfollowany
particularpattern. Inparticular, there isnoway for theProva rulebase to takeanactive roleand
communicatewiththeembedding Javacode,apart frompassingacallbackobjectto therulebase
andthelatterinvokingthecallbackwhentherulebaseneedstosenddata.
Prova3.0 includes the following simpleProvaAgent interface that imposes a contracton the
adaptorJavaobjectthatembedsaProvaengineinstance.Inaseparatemuleprovaagentsproject,
weuse
aMule
2.1
Enterprise
Service
Bus
implementation
of
this
contract.
This
allows
Prova
agents
tobeprovisionedbytheMuleESBconfigurationandcommunicatewitheachotherviaavariatyof
transportssupportedbyMule.IfanotherESB(orequivalent)implementationisrequired,allthatis
requiredisimplementingtheProvaAgentinterfacedescribedbelow.
publicinterfaceProvaAgent{ publicvoidsend(Stringdest,ProvaListterms)throwsException; publicStringgetAgentName();}
We recommendconsulting theProva3AgentImpl.javacode foran implementationsuitable for
MuleESBasitprovidesasimpleexampleoftherequiredfunctionality.AsdescribedintheSending
messages(in
particular,
see
the
discussion
on
Protocol),
the
agent
rulebase
sending
messages
using
7/31/2019 Prova 3.0 User Guide - May 2010
17/94
Provarulelanguage3.0 UsersGuide May2010
13
the"esb"protocolwillautomaticallyhitthemethodProvaAgent.send,whichthenwillpublishthem
intotheESBlayertotheindicateddestination.
@Overridepublicvoidsend(Stringdest,ProvaListterms)throwsException{ MuleClientclient=newMuleClient();
client.dispatch(dest,terms,null);}
Conversely,allmessagesreceivedbytheagentwill indicatethereceivedprotocolas"esb"but
typicallywilloverride thatwith the "async"protocol to allow for the same conversationid tobe
mappedtothesameagentthread.
publicObjectonCall(MuleEventContextcontext)throwsException{MuleMessageinbound=context.getMessage();ProvaListterms=null;if(inbound.getPayload()instanceofObjectMessage){ terms=(ProvaList)((ObjectMessage)inbound.getPayload()).getObject();}else{
terms
=(ProvaList)
context.getMessage().getPayload();
}
//AddthemessageasagoaltotheasynchronousProvaCommunicatorqueueif(!"".equals(targetProtocol)){ terms.getFixed()[1]=newProvaConstantImpl(targetProtocol);} comm.addMsg(terms);
//Wearedone,everythingisasynchronous context.setStopFurtherProcessing(true);
return
null;
}
1.4. CallingJavafromProvarulebasesProvaagentsrun inJavaso it isnaturalthatProvarulebasescanalsocallhomeandworkwith
Javadataandobjects.Thisintegrationincludes:
UsingJavatypesandclassesforProvavariables; CreatingJavaobjectsbycallingtheirconstructors; PassingProvalistsasargumentstoJavaconstructors; Invokingstaticmethods,includingobjectcreationbyusingfactorymethods; Accessingpublicstaticandinstancefields;
Using
special
built
ins
that
take
advantage
of
common
Java
classes;
AddingnewProvabuiltinsinJava.1.4.1.UsingJavatypesandclassesforProvavariables
AccordingtosomePrologexpertsandimplementers,theansenceofvariablestypinginPrologis
oneof the reasonsof its relative failure tobecome completelymainstream. Prova takes amore
practicalapproachbyallowing Javatypesexplicitlyandclearlyannotatingvariablesusingasimple
syntaxasinthefollowingexamplera001.prova::solve(a(3)).:solve(a(Number.X)).:solve(a(Integer.I)).:solve(a(Short.I)).
a(Integer.I).
7/31/2019 Prova 3.0 User Guide - May 2010
18/94
Provarulelanguage3.0 UsersGuide May2010
14
a(Double.I).
%==================%Thisprints:%yes%X=java.lang.Integer.
%X=java.lang.Double.
%I=java.lang.Integer.%no
Unificationthatincludesvariabletypesfollowsthefollowingsubsumptionrules.
1. Ifthequery(goal)is'asking'foranarrowertype,itwillnotmatchawidertypeinthetargetliteral.
2. Awiderquerywillmatchamorespecializedtargetliteral.Observe how uninstantiated variables also benefit from this with the second goal
solve(a(Number.X))matchinganyapplicablerulesthataremorespecialized.
Notethatclassesinthejava.langpackagedonotrequiretobefullqualified.Fullyqualifiedclass
names can also be used in typed variables. The following code shows how the builtins retract,
retractall,
and
insert
take
into
account
typed
variables.
:solve(ra002_1(X,Y)).:solve(ra002_2(X,Y)).:solve(ra002_3(X,Y)).
f(ws.prova.examples.IBMPortfolio.N,Integer.M).f(ws.prova.examples.Portfolio.N,M).f(ws.prova.examples.IBMPortfolio.N,Integer.M).f(2,3).
ra002_1(X,Y): println([""]), %Thefirstfactnotmoregeneralthanthisisremovedbyretractbelow
retract(f(ws.prova.examples.Portfolio.N,M)),
f(X,Y).ra002_2(X,Y): println([""]), %Factsmoregeneralthanthisarenotremovedbyretractallbelow retractall(f(ws.prova.examples.IBMPortfolio.N,Integer.M)), f(X,Y).ra002_3(X,Y): println([""]), insert(f(ws.prova.examples.Portfolio.N,Integer.M)), %DoesnotaddanythingasitsubsumesafactalreadyintheKB insert(f(ws.prova.examples.Portfolio.N,M)), f(X,Y).
%==================%Thisprints:%%X=ws.prova.examples.Portfolio.,Y=%X=ws.prova.examples.IBMPortfolio.,Y=java.lang.Integer.%X=2,Y=3%%X=ws.prova.examples.Portfolio.,Y=%X=2,Y=3%%X=2,Y=3
%
X=ws.prova.examples.Portfolio.,
Y=java.lang.Integer.
%X=ws.prova.examples.Portfolio.,Y=
7/31/2019 Prova 3.0 User Guide - May 2010
19/94
Provarulelanguage3.0 UsersGuide May2010
15
1.4.2.CreatingJavaobjectsbycallingtheirconstructorsProvaallows Javaconstructorstobe invokedusing the familiat Javasyntax,onlydropping the
newkeyword.Hereareafewexamples.L=java.util.ArrayList()DF=java.text.SimpleDateFormat("dd/MM/yyyykk:mm:ss.mmm")
Calendar=java.util.GregorianCalendar()
1.4.3.PassingProvalistsasargumentstoconstructorsWhenaProvalistispassedasanargumenttoaJavaconstructor,wefollowtheagreementthat
the toplevel elements in the supplied list are unwrapped if necessary from the Prova constant
representation to naked Java objects and the list itself is then shipped to the method (or
constructor)asJava listcontainingtheseobjects.InthecaseofordinaryJavamethodcalls,Prova
listsarepassedtothelistunchanged.Thisfragmentfromtest004.provaillustrates.List=java.util.ArrayList([1,"2"])
1.4.4.InvokingstaticmethodsHereisatypicalexampleofastaticmethodinvocation,inthisinstance,thisisafactorymethod.Model=com.hp.hpl.jena.rdf.model.ModelFactory.createDefaultModel()
1.4.5.AccessingpublicstaticandinstancefieldsPublicstaticfieldscanbeaccessedusingthefamiliarJavasyntax.Thisexampleusesafewpublic
enumerationsaswellasthestandardoutstreamasaparameterinamethod.Child1=Model.createResource(),Child1.addProperty(com.hp.hpl.jena.vocabulary.VCARD.Given,GivenName),Child1.addProperty(com.hp.hpl.jena.vocabulary.VCARD.Family,FamilyName),JohnSmith.addProperty(com.hp.hpl.jena.vocabulary.VCARD.N,Child1),Model.write(System.out),
1.4.6.UsingspecialbuiltinsthattakeadvantageofcommonJavaclassesAt the moment, there are two builtin predicates that use Java datamatching appropriate
interfaces.
TheelementbuiltincannondeterministicallyextractelementsfrominstantiatedJavaiterators.Iter=Model.listStatements(),element(Stmt,Iter),
The findall builtin accumulates the resultset of a goal in a JavaArrayList. For example, the
followingruleaccumulatesallthesolutionsofthegoal [X|Xs] inthenew listL,which isthensent
backtothecallerasawholeinonereplymessage.%Reactionruletoageneralqueryref_accrcvMsg(XID,Protocol,From,queryref_acc,[ID,[X|Xs]]):
findall([X|Xs],[X|Xs],L), sendMsg(XID,Protocol,From,reply,[ID,L]).
1.5. ExpressionsProva 3.0 can handle arithmetic expressions on the righthand side of binary operators. The
grammarisshownbelow.
expr :aterm((PLUS|MINUS)expr)?;
aterm :(MINUS?variable|number|MINUS?predicate_java_call|OPENexprCLOSE)((MULT|DIV|REM)aterm)?;
predicate_java_call : static_java_call|instance_java_call
7/31/2019 Prova 3.0 User Guide - May 2010
20/94
Provarulelanguage3.0 UsersGuide May2010
16
;
It iscurrently impossibletouseexpressions inargumentsofJavacalls.It isalsonotallowedto
useJavaconstructorsinexpressionsunlessinisolation.Herearesomeexamples.
expr001(N,M): N=M+1*2.expr001(N,M): N(M+1)*2.
expr002(N,M): N=java.lang.Math.min(1,M)+1.expr002(N,M): L=java.util.ArrayList(), L.add(2), N=L.get(0)+L.size().
1.6. GlobalconstantsGlobal constants is a new functionality in Prova. Look at the following example
globals001.prova.:solve(globals(N)).
globals(N): data($A,N).globals(N): $A=b, data($A,N).
data(a,1).
data(b,2).
Anyconstantwithnamestartingwiththe$signisaglobalconstant.Theseconstantsarepartof
the_ProvaKnowledgebaseImpl_instanceandcanbeinstantiatedpriortoparsinganewrulebaseor
modified (or added) during the execution of the code. This is accomplished by using the syntax
$Var=.
ThecodeaboveisrunfromthenewtestProvaGlobalsTest.globals001()thatinitiallysets$Ato
'a'soitreturnstwosolutions:1and2.
The intendeduseof global constants $NNN is forpassing commandline argumentsto Prova
scripts.Thisfunctionalitywillbeaddedoncethemain()runnerisaddedtothenewProvacode.
1.7.
ProvamapsfordefiningslottedtermsSlotted terms isahighlyvaluable featureof languages likeFLogic,standards (RIForRuleML),
andproducts(likeOOjDREW).Theyalsomake interoperabilitywithforwardchainingrulesystems
likeJBossRulesfareasier.
Prova 3.0 includes an implementation of slotted terms using theW3C RIF arrow expression
syntax as in the following examplemap2.prova.Note that Prova also allows to use colon ':' in
key:valueinsteadofkey>value.Thekeysarecurrentlylimitedtostrings.:solve(own(X)).
buy({buyer>'Bill',seller>'Amazon',item>'AvatarBluray'}).
keep({keeper>'Bill',item>'AvatarBluray'}).
own({owner>Person,item>Object}):
7/31/2019 Prova 3.0 User Guide - May 2010
21/94
Provarulelanguage3.0 UsersGuide May2010
17
buy({buyer>Person,seller>Merchant,item>Object}), keep({keeper>Person,item>Object}).
ThisshowsthatProvamapscanbeusedassoleargumentsofpredicates,essentiallyreplacing
positionbasedsyntaxwithonebasedonnamedarguments.Theexampleprints:X={item=AvatarBluray,owner=Bill}
Thetestmap2()inProvaBuiltins1Test.javaisbasedonthisexample.
Slottedtermsareespeciallyusefulinreactivemessaging,seethediscussiononslottedtermsinreactivemessaging.
1.8. MetadataannotationsTheoldProvaversionhadaninterestingbutsomewhatpatchyapproachtoruntimeprocessing
oftherulemetadata.Prova3.0isaimingtoimproveonthis.Thefirstquestioniswhattoannotate
with metadata? It is clear that all Prova clauses (rules and facts) should be allowed to carry
metadata.As you'll seebelow,body literals can also be annotated so thatwheneverunification
occurs,itusesmetadatamatchingifmetadataispresentonthebodyliteral.
The
examples
below
are
taken
from
a
new
test
rules/reloaded/label.prova.
This
is
the
way
metadataisaddedtorules:@label(rule1)r1(X):q(X).@label(rule2)r2(X):q(X).@label(rule3)r2(X):q(X).
Metadataisasetofannotationseachofwhichisapairdefinedas:@key(value[,value]*).Both
keys and values are arbitrary strings definedby theiroccurrence in an annotation.All rules in a
rulebaseconsultedfromafileautomaticallyhaveaspecialannotation@src(FILENAME).Apartfrom
that,allotherruleannotationsaredefinedbytheuser.Therecouldbemorethanoneuserdefined
annotationassociatedwithasinglerule.Thereisnorequirementforannotationstobeonthesame
lineastherulehead.
Now therewouldn'tbeany realuse for this ifwe couldn't somehow take thismetadata into
accountwhen
the
rulebase
is
executed.
To
achieve
that,
the
body
literals
in
arule
can
be
optionally
annotatedaswell.Hereisanexamplethatreturns3solutions(1,2,3):p1(X): @label(rule1) r1(X).q(1).q(2).q(3).
:solve(p1(X2)).
The annotationson literals (asopposed to rules) are a setof constraintson the target rules
duringunification.Foreach literalannotation, theremustbeat leastonematchbetweenavalue
listedfor
that
annotation
and
avalue
listed
for
the
same
key
in
the
target
rule.
This
is
amore
complexexamplethatalsohasthreesolutions(1,2,3):%succeedssincescopeisEITHER"rule2"OR"rule1"p2a(X): @label(rule2,rule1) r1(X).:solve(p2a(X4)).
Imagine now thatwe do not knowwhat are the target annotation values andwould like to
discoverandpossiblytracetheannotationsfortargetrulesmatchinga literal.Howabouttryingto
useavariable insteadofaconstantvalue ina literalannotation?Thefollowingreturns6solutions
whereLabel6takesvalues'rule2'and'rule3'3timeseach.p4(X,Y):
@label(Y)
r2(X).
7/31/2019 Prova 3.0 User Guide - May 2010
22/94
Provarulelanguage3.0 UsersGuide May2010
18
:solve(p4(X6,Label6)).
Observethatifamatchisfound,executioncontinuesforr2(X)asthoughthe@labelannotation
wasnotpresent.
Now since we have variables in literal annotations, we can also preassign values to these
variablesdynamically.The following code sets theannotationvalueat runtime to 'rule2' so that
only
3
solutions
for
X7
are
returned
(1,2,3).
%dynamicallysetthemetadatavalueexpectedfrommatchingrules:solve(p4(X7,rule2)).
Finally,we can also find the rulebaseof the target clause in aunification. The final example
shows howwe can constrain one annotation (@label)while enquiring on the value of another
(@src). In thisway, anymatch canbe traced from the source rulebaseof the target clause.This
returns3solutionswithSrc9settothefilenameoftherulebaseineachsolution.%getmodulelabelp6(X,Y): @src(Y)@label(rule3) r2(X).:solve(p6(X9,Src9)).
1.9. GuardsinProvaProva 3.0 implements a new inference extension called literal guards. Let's start with an
example. Imaginethatduringunification,thetargetrulematchesthesource literalbutwedonot
wanttoproceedwithfurtherevaluationunlessaguardconditionevaluatestotrue.Theguardsare
specified inasyntax that issimilar to theoneused inErlang (usingbrackets insteadof thewhen
keyword) but the semantics are more appropriate for a rule language like Prova. See
rules/reloaded/guard.provaandProvaMetadataTest.java.
@author(dev1)r1(X):q(X).@author(dev22)r2(X):q(X).@author(dev32)r2(X):s(X).
q(2).s(2).
trusted(dev1).trusted(dev22).%Authordev22istrustedbutdev32isnot,soonesolutionisfound:X1=2p1(X): @author(A) r2(X)[trusted(A)].:solve(p1(X1)).
Thisexampleusesmetadataannotationsonrulesforpredicatesr1/1andr2/1andontheliteral
r2(X)in
the
body
of
the
rule
for
p1(X)
(see
Metadata
annotations).
Since
variable
A
in
@author(A)
is
initiallyfree,itgetsinstantiatedfromthematchingtargetrule(s).OnceAisinstantiatedtothetarget
rule's @author annotation's value ('dev22', for the first r2 rule), the body of the target rule is
dynamicallynondestructivelymodifiedtoincludealltheliteralsintheguardtrusted(A)beforethe
bodystart,afterwhichtheprocessingcontinues.Sincetrusted(dev22) istruebuttrusted(dev32)is
not,onlythefirstruleforpredicater2isusedandsoonesolutionX1=2isreturnedbysolve(p1(X1)).
Guards can include arbitrary listsofProva literals including Java calls,arithmeticexpressions,
relations,andevenCUT.ThenextexampleshowshowCUTcanbeusedintheliteralguard.
a(X):qq(X).a(X):s(X).
s(2).
7/31/2019 Prova 3.0 User Guide - May 2010
23/94
Provarulelanguage3.0 UsersGuide May2010
19
%Thisexampleshowshowguardscanbeusedtoimplementa"dynamicCUT".%TheCUTintheguardisdynamicallysplicedintothestartofthetargetrulebody.%Asqq(X)hasnosolutions,theCUTpreventsfurtherbacktrackingtothesecondrulefora(X):s(X),%thatwouldhaveyieldedasolutionbutdoesnotduetothatdynamicCUT.p2(X): a(X)[!].
:solve(p2(X2)).
IftheCUTwasincludedaspartofthep2(X)ruleaftera(X)likeinthefollowingversion,thea(X)
ruleincludingqq(X)wouldhavefailedbutthesecondrulewouldhaveprovidedonesolution:2.p2(X): a(X),!.
Provaguardsplayevenamoreimportantroleinmessageandeventprocessingastheyallowthe
receivedmessagestobeexaminedbeforetheyareirrevocablyaccepted,seethedetailsinGuardsin
messageprocessing.
1.10. WorkflowsandbusinessprocessesProvaoffersafairlyuniquecombinationofprocessingtechniques,includingworkflows,reactive
messaging,event
processing
and
elements
of
functional
programming.
The
idea
is
to
give
the
users
agreatfreedomforbuildingdistributedagentsusingaholisticapproachthatdoesnotforcethemtoa
particularmethodology.
The following syntactic and semantic instruments in Prova 3.0 capture the basics and offer
uniqueadvancedfeaturesforimplementingworkflowsandbusinessprocesses.
inherentnondeterminismfordefiningprocessdivergences; Reactivemessaging; Concurrencysupport,includingpartitionedandnonpartitionedthreadpools; builtinpredicatespawnforrunningtasks; processjoin predicatejoin reactiongroupscombiningeventprocessingwithworkflows(seeeventdrivengatewaysandEventprocessingusingreactiongroups); supportfordynamiceventchannels; guardsThis Section discusses the Prova support for workflows, in particular, both simple and
sophisticatedlogicbasedpredicategateways.
1.10.1. SimplegatewaysProva includes a very simple mechanism (inspired by Joincalculus) for creating diverging
branches (parallel gateway) and processjoin points (inclusive gateways). Consider the following
simpleworkflowpresentedintheBPMNnotation.
7/31/2019 Prova 3.0 User Guide - May 2010
24/94
Pro
The
implem
:ev
pro
p
s
in
in
commun
fo
fork
s
r
fo
fork
s
r
jo
fork
s
r
jo
fork
s
r
arulelangu
following c
ntthiswor
al(process_jo
ess_join():
intln(["====
Thismessag
ndMsg(XID,s
Theresulto
Createajoi
it_join(XID,jo
Createajoi
it_join(XID,jo
Thiswillcre
NotethatP
icate
withother
rk_a_b(XID).
a_b(XID):
Taska
ndMsg(XID,s
vMsg(XID,sel
rk_c_d(XID).
a_b(XID):
Taskb
ndMsg(XID,svMsg(XID,sel
Tellthejoin
in(Me,XID,joi
c_d(XID):
Taskc
ndMsg(XID,s
vMsg(XID,sel
Tellthejoin
in(Me,XID,joi
c_d(XID):
Taskd
ndMsg(XID,svMsg(XID,sel
age3.0
ode fromp
flow.
in()).
======proc
esignalsthe
elf,0,start,[]),
theaboveis
predicatejo
in_1,[c(_),b(_
predicatejo
in_2,[c(_),d(_
atetwopara
ovadoesnot
agentsasyn
elf,0,reply,a(
,Me,reply,a(
elf,0,reply,b(,Me,reply,b(
join_1thata
n_1,b(1)).
elf,0,reply,c(1
,Me,reply,c(
join_1thata
n_1,c(1)).
elf,0,reply,d(,Me,reply,d(
rocess_join.
ss_join=====
startofthec
thatwenow
in_1withthe
]),
in_1withthe
]),
llelprocessin
runthemin
hronouslyef
),corr_a),
),corr_a),
),corr_b),),corr_b),
newpattern
),corr_c),
),corr_c),
newpattern
),corr_d),
),corr_d),
UsersG
rova uses
====="]),
nversation.
havethecon
listofrequir
listofrequir
streams.
eparatethr
ectivelyallo
isready
isready
uide
the builtin
Theenginein
versationid
edinputpatt
edinputpatt
adsbutthey
ingforpara
predicates
itializesthec
IDinitialise
ernsinthela
ernsinthela
areindepend
llelprocessin
init_join an
onversation
.
stargument.
stargument.
entandcan
g.
ay2010
20
join to
idXID.
7/31/2019 Prova 3.0 User Guide - May 2010
25/94
Provarulelanguage3.0 UsersGuide May2010
21
join(Me,XID,join_2,d(2)).
%Thefollowingrulewillbeinvokedbyjoinoncealltheinputsareassembled.join_1(Me,XID,Inputs): join(Me,XID,join_2,c(2)), println(["Joined",join_1,"forXID=",XID,"withinputs:",Inputs]).
%Thefollowingrulewillbeinvokedbyjoinoncealltheinputsareassembled.join_2(Me,XID,Inputs): println(["Joined",join_2,"forXID=",XID,"withinputs:",Inputs]).
%Atestingharnesscatchallreactionforprintingallmessages.rcvMsg(XID,Protocol,From,Performative,[X|Xs],Extra): println([Performative,[X|Xs],Extra]).Thiscodeprints:
==========process_join==========replyforconversationidprova:1:[a,1],corr_areplyforconversationidprova:1:[b,1],corr_bJoined
join_1
for
XID=prova:1
with
inputs:
[[b,1],
[c,1]]
replyforconversationidprova:1:[c,1],corr_cJoinedjoin_2forXID=prova:1withinputs:[[c,2],[d,2]]replyforconversationidprova:1:[d,1],corr_d
In the example, all tasks aremodeled as messages sent to self, i.e., the engine itself, and
acceptingthesamemessageinthebodyofthesamerule.Thiscouldbereplacedbyeitherinbody
taskexecution,spawningacomputationusingspawnorsendingarequestmessagetoanagentand
acceptinga replywith the results.Remember that rcvMsgdoesnotblock the current threadbut
waitsforamessageasynchronously,whilekeepingallthecurrentdatainthetransparentlycreated
closure.Parallelbranchingisimplementedbysimplycreatingapredicatewithmultipleclausesand
processingtherelevanttasksasynchronously.
Nowback
to
the
init_join
and
join
predicates.
The
former
initializes
ajoin
(an
inclusive
gateway)
by passing it (1) the conversationid onwhich thejoinwill be processed, (2) the exit predicate
invokedwhen thejoinconditionsareverifiedand (3)a listofjoin terms representing tokens that
needtobecomeavailablefortheexitpredicateofthejointofire.Itisentirelypossibletospecifyjoin
termscontainingarbitraryfreevariables,includinganonymousvariable'_'.
When processing reaches a point in the workflow where the join condition can be
communicatedtotheengine,thecodeusesthejoinpredicatethatacceptsthenameoftheagent,
theconversationid,thenameofthejoin,andtheconcretejointermthatcorrespondstoanewly
availablejointoken.Whentheenginedetectsthatalljointermsareavailable,itprocessestheexit
goal for the predicate corresponding to thejoin name specified at initialization (see clauses for
join_1andjoin_2).
1.10.2. Eventdrivengateways(edBPM)Prova supports ebPBMstyle of agent programming and, in fact, offersmuchmorewith the
conceptofreactiongroups.Onecouldarguethataneventdrivengatewayisasimplifiedversionofa
reactiongroup.Considerthefollowingvariationontheexampleintheprevioussection.
7/31/2019 Prova 3.0 User Guide - May 2010
26/94
Pro
Wh
dependi
detecteThe
implem
fork
r
s
r
fo
fork
r s
r
jo
fork
r
An
behavio
event a
happen
fromth
areact
Howeve
annotat
run_ba
only ex
situatio
The
this spe
workflo
impose
timeout
fork
arulelangu
t changed
ingonwhet
d,the
other
following
ntedusing
a_b(XID):
group(g)
vMsg(XID,Pr
ndMsg(XID,s
vMsg(XID,sel
rk_c_d(XID).
a_b(XID):
group(g)
vMsg(XID,PrndMsg(XID,s
vMsg(XID,sel
Tellthejoin
in(Me,XID,joi
a_b(XID):
or(g)
vMsg(XID,Pr
Rreaction
rsuchthat
rrives, due
tobethe
egrouptha
allynotint
r, there are
iondeclares
rrives,theg
ension of t
n.
beautyoft
cification, t
,eventpat
a10secon
channel.
a_b(XID):
age3.0
here is the
ertheeve
alternativeodifiedfirst
areactiong
otocol,From,
elf,0,reply,a(
,Me,reply,a(
otocol,From,elf,0,reply,b(
,Me,reply,b(
join_1thata
n_1,b(1)).
otocol,From,
groupgives
hegroupc
o the sema
lternativer
isusedfor
restedinc
subbranc
themtobe
roupasaw
he workflo
isapproac
ranslating t
tern,ormo
dstimeout
exclusive
trun_aorr
ranchis
im
halfofthe
oup.
ommand,run
),corr_a),
),corr_a),
ommand,run),corr_b),),corr_b),
newpattern
r,_).
thetwom
llectivelyw
ntics of OR,
eaction,dis
definingthe
mmonacti
es followin
partofthe
holedisapp
. Note tha
isthelinea
o the ease
egeneralre
onthegrou
UsersG
hoice that
un_barrive
ediatelydi
aboveexa
_a),
_b),
isready
ssagehand
aitsforeith
, the group
ppears.Th
semantics
nlogicsot
g either of
reactiongr
arsbutthe
we use a
rityofexte
of authori
activebeha
p,addsa
uide
the enviro
first.More
sabledso
th
pleshows
lers foreve
erofthet
asa whole
@orannot
ofthegrou
isreaction
the reactio
upwitha l
closureoft
Prova OR r
sibleseman
g and mai
ior.Forexa
notannota
ment imp
ver,assoo
atonly
one
owtheeve
tsrun_aa
oeventsto
is terminat
atedreactio
asawhole
isnotfollo
s annotate
gicalname
hefiredbra
action gro
ticvariants
tainability
mple,thef
iononthe
ses on the
aseithero
branchcan
ntdriveng
drun_ba
arrive.Wh
ed so that
nistheexit
.Inthisinst
edbyanyt
with @gr
g.Soonce
nchcontinu
p to model
hatcanbe
of the desi
llowingmo
run_bchan
ay2010
22
process
fthemis
roceed.teway is
ollective
neither
hatever
channel
ance,we
ingelse.
up (this
run_aor
sasthe
an XOR
addedto
n, be it
ification
elanda
7/31/2019 Prova 3.0 User Guide - May 2010
27/94
Provarulelanguage3.0 UsersGuide May2010
23
@group(g) rcvMsg(XID,Protocol,From,command,run_a), sendMsg(XID,self,0,reply,a(1),corr_a), rcvMsg(XID,self,Me,reply,a(1),corr_a), fork_c_d(XID).fork_a_b(XID):
@group(g)
@not
rcvMsg(XID,Protocol,From,command,run_b).fork_a_b(XID): @or(g)@timeout(10000) rcvMsg(XID,Protocol,From,or,_).fork_a_b(XID): @or(g) rcvMsg(XID,Protocol,From,timeout,_), sendMsg(XID,self,0,reply,b(1),corr_b), rcvMsg(XID,self,Me,reply,b(1),corr_b), %Tellthejoinjoin_1thatanewpatternisready join(Me,XID,join_1,b(1)).
Ifrun_aarrivesbeforethetimeout,itremainstheonlybranchasinthepreviouscase.Ifneither
run_anor_run_barrivebeforethetimeout,thetimeoutchannelproceedswiththebranchwithtaskb. Prova 3.0 includes a large collection of annotations for reaction groups that really helpwith
designingverysophisticatedworkflows.
1.10.3. PredicategatewaysIt iseasytoseewhysimplejoinsmaybequitelimiting.Imagineyouneedtoanalyzewhatjoin
tokensareavailabletothejoinandmakeadecisionusinglogicalreasoning.Furthermore,ifthefinal
joinconditionsarenotyetachieved,itwouldbegreatifwecouldreinitializethejoin,ifsomeother
conditionsareverified.Thereareknownworkflowpatterns(forexample,StructuredDiscriminator)
catalogedbyvanderAalstthatbenefitfromsuchfeatures.
Thefollowingexamplepredicate_join_concurrent.provausestheenhancedversionofthesame
workflowframeworkcomplementedbybuiltinpredicatesinit_predicate_joinandpredicate_join.
:eval(predicate_join_concurrent()).
predicate_join_concurrent(): println(["==========predicate_join_concurrent=========="]),
for([0,2],I), sendMsg(XID,async,0,request,a()), rcvMsg(XID,async,Me,reply,a()),
%Initialisethepredicatejoin:
%
XID
is
conversation
id;
%join_1istheexitpredicatethatmustbeuniqueforeachjoin; %join_predicate_1isthejoinconditions; %i1..i3aretherequiredtokens. init_predicate_join(XID,join_1,[i1(),i2(),i3()],join_predicate), println([XID]), %Thiswillcreatethreeparallelprocessingstreams. loop_a_body("Worker",XID).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Threebranchesexecutingthreeparallelactivities%%representingadivergenceintheprocess%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%
7/31/2019 Prova 3.0 User Guide - May 2010
28/94
Provarulelanguage3.0 UsersGuide May2010
24
loop_a_body(Partner,XID): switch_thread(a), println(["Branch1complete"]), predicate_join(XID,join_1,i1(),[Partner]).loop_a_body(Partner,XID):
switch_thread(b),
println(["Branch2complete"]), predicate_join(XID,join_1,i2(),[Partner]).loop_a_body(Partner,XID): switch_thread(c), println(["Branch3complete"]), predicate_join(XID,join_1,i3(),[Partner]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%RulesrepresentingtheexitbranchesoftheJOIN%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%ThefollowingrulewillbeinvokedbyjoinonceONEinputforjoin_1hasarrived.%Thisisgovernedbythefirstjoin_predicaterule.join_1(s(0),XID,Count,Inputs,[Partner]): println(["JoinedforXID=",XID,"atstate's(0)'withinputs:",Inputs]), %Reporttothetestcaserunnerthatthisstepiscomplete sendMsg(XID,self,0,job_completed,[]).%Thefollowingrulewillbeinvokedbyjoinonceallinputsforjoin_1havearrived%Thisisgovernedbythesecondjoin_predicaterule.join_1(reset,XID,Count,Inputs,[Partner]): println(["JoinedforXID=",XID,"atstate'reset'withinputs:",Inputs]), sendMsg(XID,self,0,body_a_complete,[]),
%
Report
to
the
test
case
runner
that
this
step
is
complete
sendMsg(XID,self,0,job_completed,[]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Rulesestablishingwhenthepredicatejoinreachesappropriatestates%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%
%Therulefordeterminingajoincondition.Notethatthestatemusthaveformat"s(Number)".join_predicate(XID,join_1,s(0),Msg,Waiting,Count,Complete,Params): 1=Complete.size().%Therulefordeterminingaresetcondition.Whenthisconditionisreached,theJOINisreset.
%However,
we
also
offer
achance
to
define
an
optional
JOIN
exit
branch
when
the
reset
is
reached
%(seerule2forthejoin_1predicate).join_predicate(XID,join_1,reset,Msg,Waiting,Count,Complete,Params): 0=Waiting.size().
switch_thread(A): sendMsgSync(XID,task,0,switch,[A]), rcvMsg(XID,task,From,switch,[A]).
%%%%%%%%%%%%%%%%%%ANOOPworker%%%%%%%%%%%%%%%%%%
rcvMsg(XID,Protocol,From,request,[X|Xs]):
println([rcvMsg(XID,Protocol,From,request,[X|Xs])]),
7/31/2019 Prova 3.0 User Guide - May 2010
29/94
Provarulelanguage3.0 UsersGuide May2010
25
sendMsg(XID,Protocol,0,reply,[X|Xs]).
%Atestingharnesscatchallreactionforprintingallmessages.rcvMsg(XID,Protocol,From,Performative,[X|Xs]): println([Performative,[X|Xs]]).
%A
testing
harness
catch
all
reaction
for
printing
all
messages.
rcvMsg(XID,Protocol,From,Performative,[X|Xs],Extra): println([Performative,[X|Xs],Extra]).
1.11.FunctionalprogrammingextensionsFunctionalprogrammingisallaboutbeingabletocomposefunctionality.Thisabilityisrelatedto
the glorious category theory that emphasizes maps (arrows) over objects. Being slightly
controversial,Iwouldclaimthatfunctionalprogramming languagesshouldprimarilystriveforthat
simplicitytocompose, i.e., linearlyaugmentthings,ratherthangettingboggeddown indifficultto
readsyntaxanddetailedrefinement.
TheProvaextensionforfunctionalprogrammingattemptstodoawaywiththeproliferationof
syntacticalconstructs
and
distill
that
easy
composability.
What
has
been
done
so
far
is
by
no
means
completebutitoffersanumberofimmediatelyusefulfeaturessuchas
single andmultivalued functions, the latterofferingdirect support fornondeterminismandbacktracking;
functionalcompositionwiththeextendedderivebuiltin; partialevaluation; lambdafunctions; monadicfunctions; monadicbindusingacompositionofmapandjoin; maybe,list,state,andtreemonadsaspartoftheprovidedlibrarywitheasyextensibility.In order to utilize the functional extensions in Prova, you need to consult the utility library
functional.provafrom
your
rulebase.
%Thisassumestheindicatedpathlocationforthelibrary
: eval(consult('rules/reloaded/functional.prova')).
From the source code Prova distribution, you can also run the tests in
ProvaFunctionalProgrammingTest.javatofindoutwhatisavailable.
1.11.1. RepresentingfunctionsProva allows the user to define functions using facts and rules obeying a number of simple
conventions.
1. Functionsaredefinedviarulesforarity2predicateswhosepredicatesymbolthenbecomesthe
function
symbol.
2. Thefirstargumentistheinputandthesecondargumentistheoutputofthefunction.3. If the input (output) isa simple term, thiscorresponds toaone input (output)parameter
function.
4. Otherwise, the input (output) is a Prova list, corresponding to multiple input (output)parameters.
5. Theonlyexceptionstorules4and5areProvalistsbeginningwithstringsmaybe,list,stateortree,inwhichcasethosearetreatedasasingleinputoroutputparameter.
Considersomeexamples.
double(X,XM): XM=2*X.
add([A,B],Z):
7/31/2019 Prova 3.0 User Guide - May 2010
30/94
7/31/2019 Prova 3.0 User Guide - May 2010
31/94
Provarulelanguage3.0 UsersGuide May2010
27
visibleandcanbeusedinallsubsequentfunctionsintheenclosingpipelinewhichisagreatwayto
passthedatadownstream.
%Twoequivalentforms,withoutandwithlambda%BothinstantiateL2=4derive([[add(1)],3,L2])derive([[lambda(A,add(1,A))],3,L2])
%Anexampleofpassingdatadownstream%Thisinstantiates:V3=9,V2=4,V1=2,C1=13derive( [[lambda(V1,double(V1)),lambda(V2,double(3)),lambda(V3,add(V2,V3))],2,C1])
1.11.4. SimplefunctionalcompositionInthecaseofsimplecomposition,thefunctionalpipelineiscomposedoffunctionsoperatingon
the totality of the values being passed between them. To appreciate the power of functional
composition,
we
would
like
to
pass
between
functions
compound
data
as
opposed
to
single
values.
Considerthefollowingfunction.
duplicate(X,[X,X]).
WhatevertheXvalue,the functioncreatesatwoelement listwithtwo identicalcopiesofthe
samevalue(orstructure,ifXisalsoalist).Followingisanexampleofitsuse.
%ReturnsXX=6derive( [[duplicate,add],3,XX])
Whathappenshere?First,thesimplevalue3istransformed intothe list[3,3].Thenthesetwo
numbers(3
and
3)
get
shipped
as
the
first
two
parameters
to
the
function
add,
returning
the
result.
The apparent inflexibility of always attaching the computation results to the end of the next
function'sargumentsisnicelyresolvedbyusinglambdafunctions.
%Giventhisdefinitionsecond_degree([A,B,C,X],R): R=A*X*X+B*X+C.
%Splice3asbothAandB%Thisinstantiates:Z=3,XX=7derive( [[lambda(Z,second_degree(Z,Z,1,1))],3,XX]
)Nowfinallyiftheinputisalist,thelambdafunctionneedstoacceptmorethanonevariableby
declaringitsinputasalist.
%Thisinstantiates:A=3,B=3,L11=7derive( [[duplicate,lambda([A,B],second_degree(A,B,1,1))],3,L11])%Thisalsoworksthesamewayderive( [[lambda([A,B],second_degree(A,B,1,1))],[3,3],L11])
Now
we
are
completely
ready
for
FizzBuzz,
functional
Prova
style.
We
are
going
to
show
three
waystodothesamethingandlaterdothesameagainusingtheListmonad.Notethatforisamulti
7/31/2019 Prova 3.0 User Guide - May 2010
32/94
Provarulelanguage3.0 UsersGuide May2010
28
valued function thatnondeterministically returnsall integersbetween1and100 (itsdefinition is
verysimpleandispartoftheutilitylibraryfunctional.prova).prtlnisafunctionthatechoesbackits
inputwhileprintingitfollowedbynewline.
:solve(
derive(
[[for(1,100),fizzbuzz(3,5),prtln],[],X] )).:solve( derive( [[for(1,100),lambda(I,fizzbuzz(3,5,I)),prtln],[],X] )).:solve( derive( [[for,lambda(I,fizzbuzz(3,5,I)),prtln],[1,100],X] )
).
%fizzbuzz:(M1,M2,I)>Rfizzbuzz([M1,M2,I],R): C1=ImodM1, C2=ImodM2, fizzbuzz(C1,C2,I,R).
fizzbuzz(0,0,_,fizzbuzz):!.fizzbuzz(0,_,_,fizz):!.fizzbuzz(_,0,_,buzz):!.fizzbuzz(_,_,I,I).
1.11.5. MonadicfunctionalcompositionInthecaseofmonadiccomposition,thefunctionalpipelinepassesaroundmonadicdataandis
composedoffunctionsoperatingondata insomeform"contained" inthemonadicdata.Monadic
composition in Prova is done by patternmatching the data passed between functions in the
functionalpipeline.
Toclarify,thisapproach isnotdirectlycomparabletotheoneused infunctionalprogramming
languages.Thelatterisbasedonstrongtypingenforcedatcompiletime.Provaisobviouslyquitea
bitmoredynamicsotheapproachusedhereisdatadriven.Inthefollowingdiscussion,weassume
minimal understanding of what monads are about (see, for example, this compact post:
http://www.haskell.org/haskellwiki/Monads_as_containers).
The core idea is thatmonadic functionsproduce Prova termsmatchingpredefinedpatterns
knownto
the
functional
framework.
1.12.BuiltinsreferenceThisSectionprovidesacompletereferenceforthebuiltinprimitivesintheProvalanguage.
assert/1(i)
ThisbuiltinpredicatetakesaProvalistastheonlyargumentandaddsittotherulebaserunby
the engine as a fact (a rulewithout abody) for thepredicate symbol corresponding to the first
element in the supplied list. Remember that in Prova, a standard Prologlike compound term
f(t1,...,tN)is
asyntactic
equivalent
of
alist
[f,t1,...,tN],
so
we
see
that
the
predicate
symbol
correspondstothefunctorfofthecompoundterm.NotethatProvafactscancontainfreevariables.
7/31/2019 Prova 3.0 User Guide - May 2010
33/94
Provarulelanguage3.0 UsersGuide May2010
29
TL2=javax.swing.JLabel("Results"), TL2.setAlignmentX(java.awt.Component.CENTER_ALIGNMENT), assert(label2(TL2)),
Theasserted factscanbequeried in the samewayas the regular facts thatwerepartof the
rulebaseatthetimetheProvaenginestarted.
label2(TL2), unescape("\ntest_spawn2finished.",Text),
Theassertedfactscanremovedusingretract/1orretractall/1builtinpredicates.
Comp=Event.getComponent(), %Rememberwherethepopupoccurred retractall(selected_component(_)), assert(selected_component(Comp)),
asserta/1(i)
Thisbuiltin
predicate
takes
aProva
list
as
the
only
argument
and
adds
it
in
front
of
any
other
factsforthesamepredicatetotherulebaserunbytheengineasafact(arulewithoutabody)for
the predicate symbol corresponding to the first element in the supplied list. Remember that in
Prova,astandardProloglikecompoundtermf(t1,...,tN)isasyntacticequivalentofalist[f,t1,...,tN],
soweseethatthepredicatesymbolcorrespondstothefunctorfofthecompoundterm.Notethat
Provafactscancontainfreevariables.
Thefollowingexampledemonstrates.
:solve(test008(X,Y)).
test008(X,Y): assert(symmetric(f)),
%
The
fact
below
will
be
added
higher
than
the
one
above
asserta(symmetric(g)), symmetric(X), println(["RuleA1:symmetric",X],""), symmetric(Y), println(["RuleA2:symmetric",Y],"").test008(X,Y): assert(dual(h,a)), assert(dual(h,_)), asserta(dual(h,f)), retractall(dual(_,a)), dual(X,Y),
println(["Rule
B:
dual",X,Y],"
").
Theexampleprints:
RuleA1:symmetricgRuleA2:symmetricgX=g,Y=gRuleA2:symmetricfX=g,Y=fRuleA1:symmetricfRuleA2:symmetricgX=f,Y=gRuleA2:symmetricfX=f,Y=f
RuleB:
dual
hfX=h,Y=f
7/31/2019 Prova 3.0 User Guide - May 2010
34/94
Provarulelanguage3.0 UsersGuide May2010
30
RuleB:dualhX=h,Y=
attach/3(i,i,io)
This predicate appends the Prova list in the second argument to the Prova list in the first
argument,returning
the
result
in
the
third.
Since
Prova
lists
are
held
in
arrays,
the
code
can
concatenateverylargelists.
Inthefirstargument,
thelistcanonlyhaveatailthatisalistnotafreeProvavariable, thetaillistisallowedtohaveatailbutthistailisignoredandnotcopiedtotheresultList.Inthesecondargument,
thelistcanonlyhaveatailandthetailisattachedtotheendoftheresultlist.Herearesomeexamples.
:solve(attach([1|L],[2,3],X)).
:solve(attach([1|[1,L]],[2,3],X)).
:solve(attach([1|[1|L]],[2,3],X)).
:solve(attach([1|[1|L]],[2,3|Z],X)).
Thisprints:
noL=L,X=[1,1,L,2,3]L=L,X=[1,1,2,3]L=L,Z=Z,X=[1,1,2,3|Z]
Here isaclassicexampleof towerofHanoipuzzle inProva,alsomakinguseofProva tabling
usingthecachebuiltinpredicate.
:solve(move(4,left,mid,right,Plan)).
move(0,_,_,_,[]):!.move(N,A,B,C,Plan): NM1=N1, cache(move(NM1,A,C,B,PlanL)), cache(move(NM1,B,A,C,PlanR)), attach(PlanL,[[A,C]|PlanR],Plan).
bound/1(i)
Thispredicate fails if the suppliedargument isa freeProvavariableoraProva listcontaining
Provavariables.Otherwise,itsucceeds.
Thefollowingfragmentshowshowtotestiftheargumentsuppliedtotheclauseisbound.
access_data(Type,ID,Data,CacheData): %Attempttoretrievebounddata bound(ID), Data=CacheData.get(ID), %Success,Data(whateverobjectitis)isreturned !.
byte_stream/2([i,i],o)
Thispredicate
encodes
either
an
input
string
or
aJava
ByteArrayOutputStream
using
asupplied
charsetname(see IANACharsets)andreturnsaJavaByteArrayInputStreamwrappingtheresulting
7/31/2019 Prova 3.0 User Guide - May 2010
35/94
Provarulelanguage3.0 UsersGuide May2010
31
bytearray.ThepredicateisstructuredasaProvafunction(seeFunctionalprogrammingextensions).
In the first argument, it accepts a Prova listwith two input parameters: (1) an input stringor a
ByteArrayOutputStream and (2) a charset name. The second argument is the produced
ByteArrayInputStream.
ThefollowingexamplecompressesaJavaString,storestodisk,andretrievesitback.
:solve(test_byte_stream(toto)).
test_byte_stream(Result): println(["==========byte_stream=========="]), byte_stream(["toto","UTF8"],BAIS), File=java.io.File.createTempFile("prefix","suffix"), FO=java.io.FileOutputStream(File), ZFO=java.util.zip.GZIPOutputStream(FO), copy_stream(BAIS,ZFO), println(["Compressedfilecreated."]),
FI=java.io.FileInputStream(File), ZFI=java.util.zip.GZIPInputStream(FI),
BAOS=java.io.ByteArrayOutputStream(),
copy_stream(ZFI,BAOS), byte_stream([BAOS,"UTF8"],Result), println(["Theoriginalstringreadfromthecompressedfile:",Result]).
ThefollowingtestfromProvaBuiltins1Test.javashowshowthisisrunfromJava.@Testpublicvoidbyte_stream_and_copy_stream(){ finalStringrulebase="rules/reloaded/byte_stream.prova"; finalint[]numSolutions=newint[]{1};
ProvaCommunicatorprova=newProvaCommunicatorImpl(kAgent,kPort,rulebase,ProvaCommunicatorImpl.SYNC);
List
solutions
=
prova.getInitializationSolutions();
org.junit.Assert.assertEquals(1,solutions.size()); org.junit.Assert.assertEquals(numSolutions[0],solutions.get(0).length);}
cache/2(i)
This builtin predicate provides support for tabling in Prova. It enables the literal in its only
argumentforcaching.ThecurrentimplementationinProva3.0keepsthecachedanswersetforthe
literalindefinitely.
The following example runs the Hanoi Tower puzzle for 20 disks, which would have been
prohibitivelylongifthecachepredicatewasnotused.NaiveimplementationsinHaskellorScalaalso
sufferunlesstablingisexplicitlyadded.:solve(move(20,left,mid,right,Plan)).
move(0,_,_,_,[]):!.move(N,A,B,C,Plan): NM1=N1, cache(move(NM1,A,C,B,PlanL)), cache(move(NM1,B,A,C,PlanR)), attach(PlanL,[[A,C]|PlanR],Plan).
Tablingalsohelpstoavoidinfiniteloopingincodeastheexamplebelowshows.:solve(reach(X)).
edge(a,b).
edge(c,d).edge(d,c).
7/31/2019 Prova 3.0 User Guide - May 2010
36/94
Provarulelanguage3.0 UsersGuide May2010
32
reach(a).reach(A): edge(A,B), cache(reach(B)).
ThisreturnsonlyonesolutionX=a.
capture_enum/2([i,i],io)ND
This nondeterministic predicate enumerates regular expression groups. It is structured as a
multivalued Prova function (see Functional programming extensions). In the first argument, it
acceptsaProvalistwithtwoinputparameters:aninputstringandaregularexpression.Itproduces
independentsolutions,oneeach foreachpossibleanswer in thesecondargument.Thiscreatesa
choicepointwithasmanynondeterministicbranchesastherearetokensintheinputstream.
Thefollowingexampleshowshowthisworks.
:solve(test017(Groups)).
test017(Groups):
Text="Adoodleisadoddle", %nondeterministicallyenumerateregularexpressiongroups capture_enum([Text,"(d?)(dl)"],Groups).
Thisreturns:
Groups=[,dl]Groups=[d,dl]
clone/2(i,io)
Thisbuiltinpredicateimplementsa"unidirectionalunification".Itcreatesfreshvariablesforthe
first
term
and
then
unifies
it
with
the
second
supplied
term
so
that
the
result
is
available
in
the
secondargumentwhilethefirstargumentisleftunmodified.Forexample,:solve(test_clone(must_match,add)).
test_clone(B,FunX): clone(lambda(A,[add,A,4]),lambda(1,[FunX|ArgXs])), %Atthispoint,Aisstillafreevariable,butFunXisboundtoastring'add' println([FunX,ArgXs,B],""), println(lambda(A,[add,A,4]),""), %must_matchunifieswithaconstantAsuccessfully %NotwecannotuseAastheheadvariable,otherwiseclonecannotmatchmust_matchwith1 B=A.
Thecodeaboveprintsthefollowing.
add[1,4]
must_match
lambda[add,,4]yes
Oneuseofthisbuiltinistomaplambdaexpressionsoverlists(andothermonads).Thecopyof
thelambdafunctionneedstobefreshonapplicationtoeach listelement,soclone/2achievesthis
byunifying theprovided lambdaexpression in the firstargumentwithastandard template in the
secondargument,appliestheresultinthesecondargumenttothecurrentelementusingthebuiltin
derive/3 and continuesprocessing the remainderof the listwith theoriginalunmodified lambda
expression.map([lambda(A,[Fun|Args]),list(X|As)],[B|Bs]): !, clone(lambda(A,[Fun|Args]),lambda(X,[FunX|ArgXs])),
derive([FunX,ArgXs,B]), map([lambda(A,[Fun|Args]),As],Bs).
7/31/2019 Prova 3.0 User Guide - May 2010
37/94
Provarulelanguage3.0 UsersGuide May2010
33
concat/2(i,io)
ThisbuiltinpredicatetakesaProvalistanditeratesoverthelistelements,byconvertingthemto
Javastrings,concatenating them,andunifyingthe resultwith thesecondargument. Ifthesecond
argumentisnotafreevariable,theunificationbetweentheconcatenationresultandthisargument
mayfailwhichthenfailsthebuiltin.
%Nosolutionsherer(AB): concat([a,b],AB), concat([a,c],AC), concat([a,c],AB), %Thislineis(correctly)unreachableinProva3.0 println(["1:",AB,"=",AC]).
copy/2(i,i)
ThispredicatetakesthecharacterstreamfromaJavaReaderandwritesitusingaJavaWriter.IO
exceptions
are
wrapped
in
a
RuntimeException.
The following code uses a StringWriter to capture the stream in a buffer. A mobile agent
functionalityisimplementedbysendingarulebasefragmenttoanotheragentthatthenconsultsthe
rulebasedynamicallyandrunsagoal.
upload_mobile_code(XID,Remote,File): fopen(File,Reader), Writer=java.io.StringWriter(), copy(Reader,Writer), SB=Writer.getBuffer(), sendMsg(XID,esb,Remote,upload,consult(SB))....
rcvMsg(XID,Esb,From,upload,consult(SB))
:
iam(Me), consult(SB), %Theclauseforworker/2isdefinedinthecodethattheManageruploadstothisworker worker(XID,From).
copy_stream/2(i,o)
This predicate copies a Java ByteArrayInputStream to a Java ByteArrayOutputStream. The
predicate isstructuredasaProvafunction(seeFunctionalprogrammingextensions),withthefirst
argumentasinputandthesecondargumentasoutput.
ThefollowingexamplecompressesaJavaString,storestodisk,andretrievesitback.:solve(test_byte_stream(toto)).
test_byte_stream(Result): println(["==========byte_stream=========="]), byte_stream(["toto","UTF8"],BAIS), File=java.io.File.createTempFile("prefix","suffix"), FO=java.io.FileOutputStream(File), ZFO=java.util.zip.GZIPOutputStream(FO), copy_stream(BAIS,ZFO), println(["Compres