ARL rules examples
We describe the most common statements corresponding to the BAL constructs in BAL constructs.
From parameters
BAL and ARL are equivalent in meaning, as you can see in the following comparison. The same rule condition is presented side by side:
| BAL | ARL |
|---|---|
|
|
In the previous BAL example, a new variable (b) is defined by writing the
following expression: ‘set b to 'the borrower';’. In the Miniloan
ServiceParameters, one can see that ‘the borrower’ is the verbalization of
the variable ‘borrower’, which is an instance of the BOM class
Borrower. Notice also that ‘the loan’ is a verbalization of an
instance of Loan.
If you are familiar with Java™, you can see from the previous example that ARL has some particularities:
- The identifiers are written in free text between back-quotes: as
`eligibility.minimum credit score`. - The keywords
ruleandwhenare unique to ARL. Other examples are:ruleset,signature,evaluate,from,ruleset,match,many,in,flowtask,ruletask, andaggregate. For a complete list of keywords, see ARL keywords. - The syntactic construction
$EngineData.thisallows BOM objects and ruleset parameters to be referenced. See Execution class mapping. - The declaration
b : miniloan.Borrower() from $EngineData.this.borrower;is called a binding. It meansbis a new variable whose value is the ruleset parameter‘borrower’referenced by$EngineData.this.borrower.
The ‘if’ expression in BAL corresponds to the ‘when’ expression
in the ARL translation. Both languages have a then expression:
| BAL | ARL |
|---|---|
|
|
ARL is designed to express pattern matching, which is the operating principle of the underlying
rule engine. The expression miniloan.Borrower() from $EngineData.this.borrower;
means that the ruleset parameter ‘borrower’ must be an instance of the class
Borrower, the binding: ‘b : miniloan.Borrower()’ means that if an instance of
Borrower is matched, it is referred to as ‘b’, finally the expression: ‘evaluate (
b.creditScore < 200);’ returns the value of the expression: ‘b.creditScore < 200’.
Considering that the semicolon behaves like a logical and, end-to-end these expressions mean the
same as ‘the credit score of b is less than 200’ in a java-like dialect.
Let’s go back to the notation ‘$EngineData.this’. It’s necessary to use such a
notation because there are many structures used below the keyword ‘rule’, in particular:
- EngineData to give access to BOM and ruleset parameters object
- RunningEngine to give access to methods of the underlying engine
For this reason, the keyword ‘this’ becomes ambiguous. A simple way to lift this
ambiguity is to use the prefix ‘this’. See Execution class mapping.
The action of the conditions in both languages (introduced by then) are
self-explanatory: If the condition, introduced by when or if, is
true, then the corresponding actions are taken, in the ARL version, a series of calls to methods of
the ‘Loan’ instance ‘loan’ which is, as told above, a ruleset parameter.
Match object in working memory
What happens when you modify the definitions section? Notice that the
from keyword, previously used to reference a parameter, vanishes. Additionally, the
binding b : miniloan.Borrower(); acts on each instance of Borrower
found in the working memory. (The working memory is the set of objects to which the rule engine is
applied.)
| BAL | ARL |
|---|---|
|
|
Collections
Imagine a scenario in which a single loan has several co-borrowers. The loan could be refused if one of the co-borrowers has a low credit score.
| BAL | ARL |
|---|---|
|
|
The variable ‘several co-borrowers’ is the verbalization of the variable
‘borrowers’ defined as a collection of borrowers. Noticed that as
borrowers is a collection the binding, ‘b : miniloan.Borrower() in
$EngineData.this.borrowers;’ is written with the keyword in instead of
from because in this case it is an inclusion.
Binding and loops
The following rule condition defines the variable risky borrowers, which
corresponds to borrowers whose yearly income is below 1000. If this list is not empty it prints all
its elements. In the following ARL example, the definition of this
variable is made by using a binding. The variable name followed by a colon (:), and
an expression:
`risky borrowers`:aggregate {
collect_class_1 : miniloan.Borrower($EngineData.this.borrower.yearlyIncome < 1000);
}
The expression used to define `risky borrowers` is an aggregate (see below). In the action part of the expression, there is a loop iterating over the elements of the just created variable: it has the same syntax as in Java.
Similar to the example above, in the following example, the variable b is
defined in ARL by using the binding: b : miniloan.Borrower() in
$EngineData.this.borrowers;:
| BAL | ARL |
|---|---|
|
|
Evaluate
definitions
set b to a borrower in 'several co-borrowers' ;
if
the credit score of b is less than 200
then
add "Credit score below 200" to the messages of 'the loan' ;
reject 'the loan';
The constraint on the credit score b is expressed in ARL as evaluate (
b.creditScore < 200);.
The same constraint could be done directly in the binding: b :
miniloan.Borrower(b.creditScore < 200) in $EngineData.this.borrowers; This way of
expressing constraints is often used in aggregates.
Aggregates
As in database aggregations, aggregates allow to group multiple values together to form a single value. There are various types of aggregates depending on the way values are grouped. The following aggregates are often used in BAL to ARL translations: collections, count, exists, match any.
Values can be accumulated in collections. For example, in the
following rule we want to create a collection regrouping all borrowers whose yearly income is below
a given threshold of 1000. To create this collection in ARL, we create a collection aggregate:
collect_class_1 : miniloan.Borrower($EngineData.this.borrower.yearlyIncome < 1000);
and add it to the ArrayList:
do {
java.util.ArrayList<miniloan.Borrower>{collect_class_1};
}
The result returned by the previous do statement is bound to the variable of
the binding.
| BAL | ARL |
|---|---|
|
|
Aggregation functions such as the count function can be used, for
example, in the following rule condition expression to determine whether there are 8 borrowers with
a yearly income superior to 1200. The aggregate count function counts the number of borrowers whose
yearly income is more than 12000. The where clause attached to the aggregate is
similar to the evaluate operator already defined. The boolean results of the where
clause is bound to the variable of the binding:
| BAL | ARL |
|---|---|
|
|
Exists
The operator exists tests that there is at least one item in a collection
of items. So, in the following rule testing there is at least one borrower is
translated by an 'exists' clause:
| BAL | ARL |
|---|---|
|
|
Match many
The match many instruction is used to translate decision tables. In the decision
table below, the match many instruction follows its semantic. The first case in the
first match many corresponds to the first condition debt to income
of the first two lines. If the condition is satisfied, an embedded match many
evaluates the corresponding conditions on the credit score lines. If the first
condition on the credit score line is satisfied (a credit score between 0 and 200), then a then
clause describes the action to be taken: the loan is refused.
The other match many evaluates the other conditions of the table and takes the
corresponding actions. The conditions corresponding to disabled actions in the decision table do not
have corresponding cases in the match many instruction:

ARL translation of the decision table:
rule `eligibility.repayment and score` {
ilog.rules.business_name = "repayment and score"
ilog.rules.dt = "eligibility.repayment and score"
ilog.rules.package_name = "eligibility"
status = "new"
when {
miniloan.Borrower() from $EngineData.this.borrower;
evaluate ( $EngineData.this.borrower.yearlyIncome > 0);
}
match many {
case ($EngineData.this.loan != null && ($EngineData.this.borrower != null && [0,30[.contains(($EngineData.this.loan.yearlyRepayment * 100) / $EngineData.this.borrower.yearlyIncome))) : match many {
case ($EngineData.this.borrower != null && [0,200[.contains($EngineData.this.borrower.creditScore)) : then 1{
$EngineData.this.loan.addToMessages("debt-to-income too high compared to credit score");
$EngineData.this.loan.reject();
}
}
case ($EngineData.this.loan != null && ($EngineData.this.borrower != null && [30,45[.contains(($EngineData.this.loan.yearlyRepayment * 100) / $EngineData.this.borrower.yearlyIncome))) : match many {
case ($EngineData.this.borrower != null && [0,400[.contains($EngineData.this.borrower.creditScore)) : then 3{
$EngineData.this.loan.addToMessages("debt-to-income too high compared to credit score");
$EngineData.this.loan.reject();
}
}
case ($EngineData.this.loan != null && ($EngineData.this.borrower != null && [45,50[.contains(($EngineData.this.loan.yearlyRepayment * 100) / $EngineData.this.borrower.yearlyIncome))) : match many {
case ($EngineData.this.borrower != null && [0,600[.contains($EngineData.this.borrower.creditScore)) : then 5{
$EngineData.this.loan.addToMessages("debt-to-income too high compared to credit score");
$EngineData.this.loan.reject();
}
}
case ($EngineData.this.loan != null && ($EngineData.this.borrower != null && ($EngineData.this.loan.yearlyRepayment * 100) / $EngineData.this.borrower.yearlyIncome >= 50)) : if ($EngineData.this.borrower != null && [0,800[.contains($EngineData.this.borrower.creditScore)){
then 7{
$EngineData.this.loan.addToMessages("debt-to-income too high compared to credit score");
$EngineData.this.loan.reject();
}
}
}
}