www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.dtl - Filter composition is here. :-)

reply "Matthew" <admin.hat stlsoft.dot.org> writes:
Just wanted to let the faithful (and the faithless) know that I'm getting
there. I've just got the following code to compile:

    foreach(int i; cont.select1!(DivisibleBy)(new
DivisibleBy(3)).reject(&isEven))
    {
        printf("%d ", i);
    }
    printf("\n");

yielding:

    -9 -3 3 9

from a List containing [-20, 20)

DivisibleBy is a functor, and isEven is a plain function
Jul 19 2004
next sibling parent "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
Hmm, just had an idea. Can I use a class (static) opCall on a functor to create
it, without clashing with the member (non-static) opCall?

It's only a small saving, but it'd trim

    cont.select1!(DivisibleBy)(new DivisibleBy(3)).reject(&isEven))

down to

    cont.select1!(DivisibleBy)(DivisibleBy(3)).reject(&isEven))

Ah, if only we have implicit instantiation ... ;)

"Matthew" <admin.hat stlsoft.dot.org> wrote in message
news:cdi01n$vo4$1 digitaldaemon.com...
 Just wanted to let the faithful (and the faithless) know that I'm getting
 there. I've just got the following code to compile:

     foreach(int i; cont.select1!(DivisibleBy)(new
 DivisibleBy(3)).reject(&isEven))
     {
         printf("%d ", i);
     }
     printf("\n");

 yielding:

     -9 -3 3 9

 from a List containing [-20, 20)

 DivisibleBy is a functor, and isEven is a plain function

Jul 20 2004
prev sibling parent reply "Ben Hinkle" <bhinkle mathworks.com> writes:
Is there a description/spec somewhere for select, reject, etc? What are the
use cases? What are the advantages/disadvantages of using them as opposed to
 foreach(int i, cont) {
  if (!isEven(i) && (i%3 == 0))
    printf("%d ",i);
 }
If these things are delaying the rest of DTL and they are driving fairly big
compiler changes I'd like to know more about them. Call me a party-pooper
but I'm not convinced right now that they are that big of a deal. Personally
I find the basic foreach to be much more readable.

"Matthew" <admin.hat stlsoft.dot.org> wrote in message
news:cdi01n$vo4$1 digitaldaemon.com...
 Just wanted to let the faithful (and the faithless) know that I'm getting
 there. I've just got the following code to compile:

     foreach(int i; cont.select1!(DivisibleBy)(new
 DivisibleBy(3)).reject(&isEven))
     {
         printf("%d ", i);
     }
     printf("\n");

 yielding:

     -9 -3 3 9

 from a List containing [-20, 20)

 DivisibleBy is a functor, and isEven is a plain function

Jul 20 2004
next sibling parent reply Sean Kelly <sean f4.ca> writes:
In article <cdj7b4$1h6f$1 digitaldaemon.com>, Ben Hinkle says...
Is there a description/spec somewhere for select, reject, etc? What are the
use cases? What are the advantages/disadvantages of using them as opposed to
 foreach(int i, cont) {
  if (!isEven(i) && (i%3 == 0))
    printf("%d ",i);
 }
If these things are delaying the rest of DTL and they are driving fairly big
compiler changes I'd like to know more about them. Call me a party-pooper
but I'm not convinced right now that they are that big of a deal. Personally
I find the basic foreach to be much more readable.

It might actually be kind of nice if we could do something like this: int main() { int[char[]] map; map["a"] = 1; map["b"] = 2; map["c"] = 3; foreach( int value; map["a".."b"] ) { printf( "%d\n", value ); } return 0; } The opSlice extension would largely remove the need for this select() method. Sean
Jul 20 2004
parent reply "Ben Hinkle" <bhinkle mathworks.com> writes:
"Sean Kelly" <sean f4.ca> wrote in message
news:cdjgfc$1li3$1 digitaldaemon.com...
 In article <cdj7b4$1h6f$1 digitaldaemon.com>, Ben Hinkle says...
Is there a description/spec somewhere for select, reject, etc? What are


use cases? What are the advantages/disadvantages of using them as opposed


 foreach(int i, cont) {
  if (!isEven(i) && (i%3 == 0))
    printf("%d ",i);
 }
If these things are delaying the rest of DTL and they are driving fairly


compiler changes I'd like to know more about them. Call me a party-pooper
but I'm not convinced right now that they are that big of a deal.


I find the basic foreach to be much more readable.

It might actually be kind of nice if we could do something like this: int main() { int[char[]] map; map["a"] = 1; map["b"] = 2; map["c"] = 3; foreach( int value; map["a".."b"] ) { printf( "%d\n", value ); } return 0; } The opSlice extension would largely remove the need for this select()

 Sean

Associative arrays don't have any defined ordering to the entries - which I assume is what you are requesting. Using the C++ terminology a "map" is a sorted associative array. In the "minimal template library" I just started your code would work fine if map is declared as type Map!(char[].int) instead of int[char[]]. Eventually I'd also like to add the equivalent to Java's LinkedHashMap, which is a hashtable that uses the insertion order for slicing and foreach (the usual Map implementation use trees which have O(log(n)) behavior instead of a hashtable's O(1)). One wrinkle about slicing with keys: the slice includes the last key. This contrasts with the usual D array slicing behavior where x[1..5] doesn't include x[5] in the slice. So your example above would print 1 and 2. I went with this behavior since 1) it would be a pain for users to have to get the next key after the last one in the slice and 2) what is the key that means "one after the last key in the map?" For slicing Lists and Maps I went with the rule that any integer slicing uses the regular D style of excluding the right endpoint but for non-integer slicing it includes the right endpoint.
Jul 20 2004
parent reply Sean Kelly <sean f4.ca> writes:
In article <cdjmbj$1o2i$1 digitaldaemon.com>, Ben Hinkle says...
"Sean Kelly" <sean f4.ca> wrote in message
news:cdjgfc$1li3$1 digitaldaemon.com...
 In article <cdj7b4$1h6f$1 digitaldaemon.com>, Ben Hinkle says...
Is there a description/spec somewhere for select, reject, etc? What are


use cases? What are the advantages/disadvantages of using them as opposed


 foreach(int i, cont) {
  if (!isEven(i) && (i%3 == 0))
    printf("%d ",i);
 }
If these things are delaying the rest of DTL and they are driving fairly


compiler changes I'd like to know more about them. Call me a party-pooper
but I'm not convinced right now that they are that big of a deal.


I find the basic foreach to be much more readable.

It might actually be kind of nice if we could do something like this: int main() { int[char[]] map; map["a"] = 1; map["b"] = 2; map["c"] = 3; foreach( int value; map["a".."b"] ) { printf( "%d\n", value ); } return 0; } The opSlice extension would largely remove the need for this select()

 Sean

Associative arrays don't have any defined ordering to the entries - which I assume is what you are requesting. Using the C++ terminology a "map" is a sorted associative array. In the "minimal template library" I just started your code would work fine if map is declared as type Map!(char[].int) instead of int[char[]].

Yup. I had thought that the implementation might be something like: int[] opSlice( char[] from, char[] to ) { char[] keys = map.keys; keys.sort(); // binary search for 'from' // binary search for 'to' // construct and return the requested range [from..to] } The obvious problem is that the range wouldn't be a slice of the actual map, but rather a copy. And sadly, I can't think of an easy way around this.
One wrinkle about slicing with keys: the slice includes the last key. This
contrasts with the usual D array slicing behavior where x[1..5] doesn't
include x[5] in the slice. So your example above would print 1 and 2.

Good point. And there's no easy way around this for associative arrays.
I went with this behavior since
1) it would be a pain for users to have to get the next key after the last
one in the slice and
2) what is the key that means "one after the last key in the map?"

Yup. Without begin and end properties we're kind of stuck in this regard. And I guess since the built-in contaners are really hash maps, asking for a sorted range is kind of silly anyway. And I suppose we could get away with something like this for a tree-based map: class Map { size_t length(); key_type key( int pos ); value_type value( int pos ); value_type[] opSlice( int b, int e ); } Thus faking it a bit by using indexes as iterators. Sean
Jul 20 2004
parent "Ben Hinkle" <bhinkle mathworks.com> writes:
 Yup.  I had thought that the implementation might be something like:

 int[] opSlice( char[] from, char[] to )
 {
 char[] keys = map.keys;
 keys.sort();
 // binary search for 'from'
 // binary search for 'to'
 // construct and return the requested range [from..to]
 }

 The obvious problem is that the range wouldn't be a slice of the actual

 rather a copy.  And sadly, I can't think of an easy way around this.

Actually as I have it now the slice of a Map!(K,V) has type Map!(K,V). A Map has a pointer to the root, a left and right node pointer and a compare function. This is a pretty big struct but I think it is worth it. The relevant parts of Map are: struct Map(K,V) { Node!(K,V) root, begin, end; CompareFcn cmp; Map opSlice(K a, K b) { Map res; ... look up the node for a and b and fill in res ... return res; } int opApply(int delegate(inout V val) dg) { ... loop from this.begin to this.end (with null checks) and apply dg ... } } I also have opSlice and opIndex with integer indices but it is slower since to find the Nth node it crawls over the tree from left to right.
One wrinkle about slicing with keys: the slice includes the last key.


contrasts with the usual D array slicing behavior where x[1..5] doesn't
include x[5] in the slice. So your example above would print 1 and 2.

Good point. And there's no easy way around this for associative arrays.
I went with this behavior since
1) it would be a pain for users to have to get the next key after the


one in the slice and
2) what is the key that means "one after the last key in the map?"

Yup. Without begin and end properties we're kind of stuck in this regard.

 I guess since the built-in contaners are really hash maps, asking for a

 range is kind of silly anyway.  And I suppose we could get away with

 like this for a tree-based map:

 class Map {
 size_t length();
 key_type key( int pos );
 value_type value( int pos );
 value_type[] opSlice( int b, int e );
 }

 Thus faking it a bit by using indexes as iterators.


 Sean

Jul 20 2004
prev sibling parent "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
"Ben Hinkle" <bhinkle mathworks.com> wrote in message
news:cdj7b4$1h6f$1 digitaldaemon.com...
 Is there a description/spec somewhere for select, reject, etc? What are the
 use cases? What are the advantages/disadvantages of using them as opposed to
  foreach(int i, cont) {
   if (!isEven(i) && (i%3 == 0))
     printf("%d ",i);
  }

I've borrowed the terminology from Ruby. I don't really care what they're called in the long run, just using them for now.
 If these things are delaying the rest of DTL and they are driving fairly big
 compiler changes I'd like to know more about them. Call me a party-pooper
 but I'm not convinced right now that they are that big of a deal. Personally
 I find the basic foreach to be much more readable.

You're right, and I intend to release 0.1 with minimal bells and whistles this weekend.
 "Matthew" <admin.hat stlsoft.dot.org> wrote in message
 news:cdi01n$vo4$1 digitaldaemon.com...
 Just wanted to let the faithful (and the faithless) know that I'm getting
 there. I've just got the following code to compile:

     foreach(int i; cont.select1!(DivisibleBy)(new
 DivisibleBy(3)).reject(&isEven))
     {
         printf("%d ", i);
     }
     printf("\n");

 yielding:

     -9 -3 3 9

 from a List containing [-20, 20)

 DivisibleBy is a functor, and isEven is a plain function


Jul 29 2004