Look at your responses i would say ignore the content of the examples,
they are there just to illustrate the syntax not to show a valid use
case or scenario. What I'm doing is looking to other languages to see
what works there and try to bring them across, the CEP type uses cases
rely a lot more on functional programming capabilities.
On 31/10/2010 13:01, Wolfgang Laun wrote:
Hello Mark,
I've been thinking about this, on and off, for 5 days now, and I still
fail to see the benefits. Perhaps there are more convincing use cases
than those in your original mail?
Notice that the "for" scope now contains two kinds of bindings: one that
is strictly local to for(...) (bi below) and another one that must be
exported
such as the binding $s in
for( bi : BasketItem( customer == $c ); $s = sum( $bi.price); )
We can certainly
make it:
$s : sum(....)
My thinking is we still need to create a sytnax to assign the results of
the expression when it returns a collection, instead of iterating it.
For this I was thinking of introducting:
$var = someexpr;
We can't do the following as there isn't enough of a differentiator in
the syntax between normal patterns.
$var : someexpr;
But we can do = for assignment of expr, but keep : for bindings of a
functional result. Just seeing how different things look.
This will be confusing.
I fail to see the usefulness of filter() in
for( $b2 : BasketItem( customer == $c ); filter( $b2, $b2.price >
100) )
filter is just a function, like min, max and average, it's not special.
Functional programming has a number of higher order functions, filter,
map and fold. There is nothing extra to support that, so it's just added
for completeness to show we could/can do it.
where one can better (and perhaps even more efficiently) write
for( $b2 : BasketItem( customer == $c, price > 100) )
The filter function was
just an example for completeness, it could have
been any function name.
I don't understand what this construct should achieve:
$r = $bi | map( $, $.price * 2) | filter( $, $.price < 100);
I wouldn't
take the example as "best practice"or actually meaningful I
was just trying to illustrate the syntax.
Given that $bi iterates over BasketItem objects, the first map would
create
a numeric value by doubling $bi.price, so I suppose the next pipeline
transmits
numbers so that filtering applies to - what? java.lang.Number? Then it
can't be
$.price;
The contents is automatically passed into the function. The first
argument is what the higher order "map" function would store, the second
one is the modifier. Typically "map" is single argument map( * 2 ), but
I can't see how that would work for our syntax, especially when passing
objects instead of values.
it could be $.floatValue or similar. But again: the entire selection
could be written as a constraint of the BaskerItem pattern. Creating a
collection just for determining a count isn't straightforward.
The idea of accumulate is to produce a scalar result from processing a
collection of facts.
It would indeed be useful to extend this so that a result
tuple can be constructed. But this could be achieved by a complex
accumulate function that returns an object with multiple fields;
in fact, min/max/count/avg/sum can be wrapped into a single function
"stats" returning an object of class "Statistics" with appropriate
fields.
Any filtering on the result can be written as a constraint on that
temporary fact pattern of type Statistics, e.g.:
Statistics( $min: min, $max: max )
from accumulate( $bi: BasketItem( $p: price ) stats( $p ) )
that's something
that can be achieved now, but requires plumbing from
the end user. Multiple functions support would avoid that and is what
people from other products would expect. The last part of the acc
provides the propagation constraint, it's sugar to avoid verbosity.
All that remains is the syntactic sugar that's provided by
x in [0..4]
y in [0..4]
$c : Cell( row == y, col == x );
as a on-the-fly pattern for selecting other patterns. Again, this could be
written more concisely as
Don't take the example as "best practice".
It's showing that 'in', which
is the same as 'from', can look more compact and is what people from a
more functional world would expect.
i'm thinking of allowing 'from' and 'in' to be used interchangable.
Where 'from' would be used with "from entry-point" where as 'in'
for
iterationg the results of an expression.
CEP cases can also need specific ordering, the example below could
find the cells in any order.
$c : Cell( row >= 0 && <= 4, col >= 0 &&
<= 4 )
and a (minor) extension such as a set expression might simplify this:
$c : Cell( row in [0..4], col in [0,1,2,3,4] )
Regards
Wolfgang
On 26 October 2010 01:36, Mark Proctor <mproctor(a)codehaus.org
<mailto:mproctor@codehaus.org>> wrote:
We are thinking of moving "accumulate" to a simple "for" keyword.
We
might allow 'in' and 'from' to be used interchangably and allow
';' semi
colons to separate the sections. I'm also wondering ho we could allow
function pipelines for the function part of the element. We also need
type inference and "default" return values.
So here are some code snippets to show what I'm thinking, as
improvements over what we do with accumulate now.
// Simple 'or' very simlar to accumulate before. ; for section
separating. With a new boolean section at the end to decide whether to
propagate or not. Will probably use '=' for function assignments.
$c : Customer()
for( $bi : BasketItem( customer == $c );
$s = sum( $bi.price);
$s > 100 )
// Multiple functions are ofcourse allowed
$c : Customer()
for( $bi : BasketItem( customer == $c );
$mn =min( $bi.price),
$mx = max( $bi.price); )
// As are multiple patterns, and as before patterns can come 'from' an
expression and with type inference we can get some nice compact text:
for ( x in [0..4]
y in [0..4]
$c : Cell( row == y, col == x );
$avg = avg( $cell.value );
$avg > 100 )
The above is possible now with the following:
Integer( this > 100) from
accumulate( x : Integer() from [0, 1, 2, 3, 4]
y : Integer() from [0, 1, 2, 3, 4],
$c : Cell( row == y, col == x ),
avg( $c.value) )
I think the proposed additions reall help with declarative
readability.
The normal chaining of elements is supported:
$c : Customer()
for( $b1 : BasketItem() in
for( $b2 : BasketItem( customer == $c );
filter( $b2, $b2.price > 100); );
$a = avg( $b1.price ); )
'for' will have a default return type for each bound function. In this
case it returns a single value $a, if there are multiple bound results
an array/map must be used for access.
I also think we should allow pipelineing of functions, much as you
would
do in a normal functional programming, possibly using haskell like
"stream fusion" capable functions.
// '$' refers to the magic contents of the function which is
"piped" in.
So $bi is piped to map, $ refers to each value evaluated in the
function, with type inference. 'map' results are piped to
'filter'. The
final results are assigned to $r.
$c : Customer()
for( $bi : BasketItem( customer == $c );
$r = $bi | map( $, $.price * 2) |
filter( $, $.price < 100);
$r.size > 100 )
More ideas welcome :) But I think this opens up some very interesting
areas for DRL, with something that will hopefully feel more
natural for
developers.
Mark
_______________________________________________
rules-dev mailing list
rules-dev(a)lists.jboss.org <mailto:rules-dev@lists.jboss.org>
https://lists.jboss.org/mailman/listinfo/rules-dev
_______________________________________________
rules-dev mailing list
rules-dev(a)lists.jboss.org
https://lists.jboss.org/mailman/listinfo/rules-dev