I've updated the blog with more details of how those if and if/else rules translate to
normal rules - so people can see the behaviour.
Mark
On 7 Sep 2012, at 18:49, Mark Proctor <mproctor(a)codehaus.org> wrote:
While this uses labelled consequences, in the future we will also
look at inline anonymous ones - which is more similar to what wolfgang proposed. I see no
reason why both can't be used.
The keyword 'do' was chosen, as it was felt that using 'then' other than
from the actual consequence block would be harder to read - when it's used on the
LHS.
rule "Give free parking to customers older than 60 and 10% discount to golden ones
among them"
when
$customer : Customer( age > 60 )
if ( type == "Golden" ) do[giveDiscount]
$car : Car ( owner == $customer )
then
modify($car) { setFreeParking( true ) };
then[giveDiscount]
modify($customer) { setDiscount( 0.1 ) };
end
rule "Give free parking to customers older than 60 and 10% discount to golden ones
among them"
when
$customer : Customer( age > 60 )
if ( type == "Golden" ) do {
modify($customer) { setDiscount( 0.1 ) };
}
$car : Car ( owner == $customer )
then
modify($car) { setFreeParking( true ) };
end
Mark
On 7 Sep 2012, at 18:45, Mark Proctor <mproctor(a)codehaus.org> wrote:
>
http://blog.athico.com/2012/09/conditional-named-consequences-in.html
>
> (Conditional) Named consequences in Drools 5.5
> Posted by Mario Fusco
> Until now Drools rules have been always expressed in the form:
> rule "name"
> when
> LHS (conditional element)
> then
> RHS (consequence)
> end
> Sometimes this could be somewhat limiting and leads to verbose and difficult to be
maintained repetitions like in the following example:
> rule "Give 10% discount to customers older than 60"
> when
> $customer : Customer( age > 60 )
> then
> modify($customer) { setDiscount( 0.1 ) };
> end
>
> rule "Give free parking to customers older than 60"
> when
> $customer : Customer( age > 60 )
> $car : Car ( owner == $customer )
> then
> modify($car) { setFreeParking( true ) };
> end
> It is already possible to partially overcome this problem by making the second rule
extending the first one like in:
> rule "Give 10% discount to customers older than 60"
> when
> $customer : Customer( age > 60 )
> then
> modify($customer) { setDiscount( 0.1 ) };
> end
>
> rule "Give free parking to customers older than 60"
> extends "Give 10% discount to customers older than 60"
> when
> $car : Car ( owner == $customer )
> then
> modify($car) { setFreeParking( true ) };
> end
> Anyway, starting from Drools 5.5, it is possible to define more labelled consequences
other than the default one in a single rule, so, for example, the 2 former rules can be
compacted in only one like it follows:
> rule "Give 10% discount and free parking to customers older than 60"
> when
> $customer : Customer( age > 60 )
> do[giveDiscount]
> $car : Car ( owner == $customer )
> then
> modify($car) { setFreeParking( true ) };
> then[giveDiscount]
> modify($customer) { setDiscount( 0.1 ) };
> end
> This last rule has 2 consequences, the usual default one, plus another one named
"giveDiscount" that is activated, using the keyword do, as soon as a customer
older than 60 is found in the knowledge base, regardless of the fact that he owns a car or
not. The activation of a named consequence can be also guarded by an additional condition
like in this further example:
> rule "Give free parking to customers older than 60 and 10% discount to golden
ones among them"
> when
> $customer : Customer( age > 60 )
> if ( type == "Golden" ) do[giveDiscount]
> $car : Car ( owner == $customer )
> then
> modify($car) { setFreeParking( true ) };
> then[giveDiscount]
> modify($customer) { setDiscount( 0.1 ) };
> end
> The condition in the if statement is always evaluated on the pattern immediately
preceding it. In the end this last, a bit more complicated, example shows how it is
possible to switch over different conditions using a nested if/elsestatement:
> rule "Give free parking and 10% discount to over 60 Golden customer and 5% to
Silver ones"
> when
> $customer : Customer( age > 60 )
> if ( type == "Golden" ) do[giveDiscount10]
> else if ( type == "Silver" ) break[giveDiscount5]
> $car : Car ( owner == $customer )
> then
> modify($car) { setFreeParking( true ) };
> then[giveDiscount10]
> modify($customer) { setDiscount( 0.1 ) };
> then[giveDiscount5]
> modify($customer) { setDiscount( 0.05 ) };
> end
> Here I wanted to give a 10% discount AND a free parking to Golden customers over 60,
but only a 5% discount (without free parking) to the Silver ones. I achieved this result
by activating the consequence named "giveDiscount5" using the keyword break
instead of do. In fact do just schedules a consequence in the agenda, allowing the
remaining part of the LHS to continue of being evaluated as per normal, while break also
blocks any further pattern matching evaluation. Note, of course, that the activation of a
named consequence not guarded by any condition with break doesn't make sense (and
generates a compile time error) since otherwise the LHS part following it would be never
reachable.