[rules-dev] exploring functional programming

Wolfgang Laun wolfgang.laun at gmail.com
Sun Oct 31 09:01:52 EDT 2010


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); )

This will be confusing.


I fail to see the usefulness of filter() in

   for( $b2 : BasketItem( customer == $c ); filter( $b2, $b2.price > 100) )

where one can better (and perhaps even more efficiently) write

   for( $b2 : BasketItem( customer == $c, price > 100) )

I don't understand what this construct should achieve:

    $r = $bi | map( $, $.price * 2) | filter( $, $.price < 100);

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; 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 ) )

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
  $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 at 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 at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/rules-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/rules-dev/attachments/20101031/35379e35/attachment.html 


More information about the rules-dev mailing list