Re: Dynamic chain for ranges?

2022-06-13 Thread Ola Fosheim Grøstad via Digitalmars-d-learn
On Monday, 13 June 2022 at 14:03:13 UTC, Steven Schveighoffer 
wrote:
Merge sort only works if it's easy to manipulate the structure, 
like a linked-list, or to build a new structure, like if you 
don't care about allocating a new array every iteration.


The easiest option is to have two buffers that can hold all 
items, in the last merge you merge back to the input-storage. But 
yeah, it is only «fast» for very large arrays.




Re: Dynamic chain for ranges?

2022-06-13 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/13/22 9:44 AM, Ola Fosheim Grøstad wrote:

On Monday, 13 June 2022 at 13:22:52 UTC, Steven Schveighoffer wrote:
I would think sort(joiner([arr1, arr2, arr3])) should work, but it's 
not a random access range.


Yes, I got the error «must satisfy the following constraint: 
isRandomAccessRange!Range`».


It would be relatively easy to make it work as a random access range if 
arr1, arr2, etc were fixed size slices.


Or I guess, use insertion-sort followed by merge-sort.


Merge sort only works if it's easy to manipulate the structure, like a 
linked-list, or to build a new structure, like if you don't care about 
allocating a new array every iteration.


-Steve


Re: Dynamic chain for ranges?

2022-06-13 Thread Ola Fosheim Grøstad via Digitalmars-d-learn
On Monday, 13 June 2022 at 13:22:52 UTC, Steven Schveighoffer 
wrote:
I would think sort(joiner([arr1, arr2, arr3])) should work, but 
it's not a random access range.


Yes, I got the error «must satisfy the following constraint: 
isRandomAccessRange!Range`».


It would be relatively easy to make it work as a random access 
range if arr1, arr2, etc were fixed size slices.


Or I guess, use insertion-sort followed by merge-sort.





Re: Dynamic chain for ranges?

2022-06-13 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/13/22 4:51 AM, Ola Fosheim Grøstad wrote:
Is there a dynamic chain primitive, so that you can add to the chain at 
runtime?


Context: the following example on the front page is interesting.

```d
void main()
{
     int[] arr1 = [4, 9, 7];
     int[] arr2 = [5, 2, 1, 10];
     int[] arr3 = [6, 8, 3];
     sort(chain(arr1, arr2, arr3));
     writefln("%s\n%s\n%s\n", arr1, arr2, arr3);
}
```

But it would be much more useful in practice if "chain" was a dynamic 
array.




`chain` allows ranges of different types.
`joiner` should be the equivalent for a dynamic range of ranges of the 
same type.


I would think sort(joiner([arr1, arr2, arr3])) should work, but it's not 
a random access range. Most likely because the big-O constants are no 
longer constant.


-Steve


Re: Dynamic chain for ranges?

2022-06-13 Thread Ola Fosheim Grøstad via Digitalmars-d-learn

On Monday, 13 June 2022 at 09:08:40 UTC, Salih Dincer wrote:
On Monday, 13 June 2022 at 08:51:03 UTC, Ola Fosheim Grøstad 
wrote:


But it would be much more useful in practice if "chain" was a 
dynamic array.


Already so:


I meant something like: chain = [arr1, arr2, …, arrN]

I don't use ranges, but I thought this specific use case could be 
valuable.


Imagine you have a chunked datastructure of unknown lengths, and 
you want to "redistribute" items without reallocation.




Re: Dynamic chain for ranges?

2022-06-13 Thread Salih Dincer via Digitalmars-d-learn
On Monday, 13 June 2022 at 08:51:03 UTC, Ola Fosheim Grøstad 
wrote:


But it would be much more useful in practice if "chain" was a 
dynamic array.


Already so:

```d
int[] arr = [4, 9, 7, 5, 2, 1, 10, 6, 8, 3];

int[] arr1 = arr[0..3];
int[] arr2 = arr[3..7];
int[] arr3 = arr[7..$];

sort(chain(arr1, arr2, arr3));
writefln("%s\n%s\n%s\n", arr1, arr2, arr3);
typeid(arr).writeln(": ", arr);
writeln(&arr[0], " == ", &arr1[0]);

/* Print Out:
[1, 2, 3]
[4, 5, 6, 7]
[8, 9, 10]

int[]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
7F7FBE348000 == 7F7FBE348000
*/
```


Dynamic chain for ranges?

2022-06-13 Thread Ola Fosheim Grøstad via Digitalmars-d-learn
Is there a dynamic chain primitive, so that you can add to the 
chain at runtime?


Context: the following example on the front page is interesting.

```d
void main()
{
int[] arr1 = [4, 9, 7];
int[] arr2 = [5, 2, 1, 10];
int[] arr3 = [6, 8, 3];
sort(chain(arr1, arr2, arr3));
writefln("%s\n%s\n%s\n", arr1, arr2, arr3);
}
```

But it would be much more useful in practice if "chain" was a 
dynamic array.




Re: bool empty() const for ranges

2021-11-26 Thread Steven Schveighoffer via Digitalmars-d-learn

On 11/26/21 5:44 AM, Salih Dincer wrote:

Hi All;

I have two questions that make each other redundant. Please answer one 
of them. I'm implementing ```bool empty() const``` for ranges as below:


```d
   bool empty() // const
   {
     bool result;

     if(!head)
     {
   result = true;
   fastRewind();
     }
     return result; // head ? false : true;
   }
```
* Is the const essential for ranges?


No, there is no specification of whether any range methods have to be 
const. As Stanislav says, it is only a requirement that subsequent calls 
return the same value as long as popFront has not been called.


* Is it possible to rewind the pointer (```Node * head;```) when my head 
is empty by the const?


If const is set, then any members are treated as const, and anything 
they point to are treated as const. So no.


That being said, if `fastRewind` changes `empty` from true to false, the 
method is invalid.


-Steve


Re: bool empty() const for ranges

2021-11-26 Thread Stanislav Blinov via Digitalmars-d-learn

On Friday, 26 November 2021 at 10:44:10 UTC, Salih Dincer wrote:


* Is the const essential for ranges?
* Is it possible to rewind the pointer (```Node * head;```) 
when my head is empty by the const?


`empty` is not required to be `const`, but it is required to 
yield the same result if called multiple times without mutating 
the range (see 
https://dlang.org/phobos/std_range_primitives.html#.isInputRange). In other words, you really ought not to mutate the range in implementation of `empty`, or at least not to the extent you seem to want to.


bool empty() const for ranges

2021-11-26 Thread Salih Dincer via Digitalmars-d-learn

Hi All;

I have two questions that make each other redundant. Please 
answer one of them. I'm implementing ```bool empty() const``` for 
ranges as below:


```d
  bool empty() // const
  {
bool result;

if(!head)
{
  result = true;
  fastRewind();
}
return result; // head ? false : true;
  }
```
* Is the const essential for ranges?
* Is it possible to rewind the pointer (```Node * head;```) when 
my head is empty by the const?


Thanks...


Re: Idiomatic error handling for ranges

2018-04-05 Thread rumbu via Digitalmars-d-learn

On Thursday, 5 April 2018 at 17:36:56 UTC, Seb wrote:

On Thursday, 5 April 2018 at 17:06:04 UTC, rumbu wrote:
Is there a standard way to handle errors in a chain of range 
transformations?


[...]


Are you aware of ifThrown?

https://dlang.org/phobos/std_exception.html#ifThrown

It's not perfect, but imho a nice start and one of the places 
where lazy really shines.


Thanks, ifThrown is perfect.


Re: Idiomatic error handling for ranges

2018-04-05 Thread Seb via Digitalmars-d-learn

On Thursday, 5 April 2018 at 17:06:04 UTC, rumbu wrote:
Is there a standard way to handle errors in a chain of range 
transformations?


[...]


Are you aware of ifThrown?

https://dlang.org/phobos/std_exception.html#ifThrown

It's not perfect, but imho a nice start and one of the places 
where lazy really shines.


Re: Idiomatic error handling for ranges

2018-04-05 Thread Timoses via Digitalmars-d-learn

On Thursday, 5 April 2018 at 17:06:04 UTC, rumbu wrote:
Is there a standard way to handle errors in a chain of range 
transformations?


Let's say I want to read some comma separated numbers from a 
file.


auto myArray = file.byLine().splitter().map!(to!int).array();

Now, besides fatal errors (like I/O), let's suppose I want to 
handle some errors in a silent way:

- skip unicode decoding errors;
- assume blank records with 0;
- skip the line entirely if the conversion to int is not 
possible;


I can catch UTFException, ConvException or 
ConvOverflowException for the entire syntax chain but there are 
some disadvantages:
- I don't know exactly which of the chain members thrown the 
exception;

- I cannot skip/handle the error and continue;

The only solution I thought about is to break the nice chain 
syntax and handle errors on each of the chain members, but I 
wonder if there is probably another way.


Thanks.


You could use predicates:

```
string list = "3, 5, 1, , not a number, 100";

int[] numbers = list.split(",").filter!((entry) {
if (!isNumeric(entry.strip))
return false;
else // ... even more cases?
return true;
})
.map!((e) => e.strip.to!int).array;

assert(numbers == [3, 5, 1, 100]);
```
https://run.dlang.io/gist/413282d9726dbac137bf5f35033a8eea


Idiomatic error handling for ranges

2018-04-05 Thread rumbu via Digitalmars-d-learn
Is there a standard way to handle errors in a chain of range 
transformations?


Let's say I want to read some comma separated numbers from a file.

auto myArray = file.byLine().splitter().map!(to!int).array();

Now, besides fatal errors (like I/O), let's suppose I want to 
handle some errors in a silent way:

- skip unicode decoding errors;
- assume blank records with 0;
- skip the line entirely if the conversion to int is not possible;

I can catch UTFException, ConvException or ConvOverflowException 
for the entire syntax chain but there are some disadvantages:
- I don't know exactly which of the chain members thrown the 
exception;

- I cannot skip/handle the error and continue;

The only solution I thought about is to break the nice chain 
syntax and handle errors on each of the chain members, but I 
wonder if there is probably another way.


Thanks.







Re: for ranges

2015-01-23 Thread Steven Schveighoffer via Digitalmars-d-learn

On 1/23/15 4:44 AM, ixid wrote:

On Thursday, 22 January 2015 at 16:41:49 UTC, Russel Winder wrote:

Playing with factorial implementations, as you do. I had a D
implementation using ulong. Not sensible obviously since overflow is a
bit of a problem. But the code worked, as did the tests. Now converting
to BigInt and…

The standard explicit iteration form uses a loop:

for(i; 2..n+1)

for n = 0 or 1 this loop doesn't loop since the range is [,). However
for BigInt:

for(i; two..n + one)

the loop starts at 0 and just keeps on going. This is clearly not good.

Am I having a mental breakdown or is this a real bug?


In general it feels as if BigInt needs more work as it doesn't
work with simple generic code in too many cases. Templates get
confused by invocation with a literal and a BigInt for example
when it should have a single type. Literals feel too strongly
typed or too weakly implicitly convertible.


This is not a BigInt problem, it's an inconsistency with foreach range. 
See my earlier post.


-Steve


Re: for ranges

2015-01-23 Thread ixid via Digitalmars-d-learn

On Thursday, 22 January 2015 at 16:41:49 UTC, Russel Winder wrote:

Playing with factorial implementations, as you do. I had a D
implementation using ulong. Not sensible obviously since 
overflow is a
bit of a problem. But the code worked, as did the tests. Now 
converting

to BigInt and…

The standard explicit iteration form uses a loop:

for(i; 2..n+1)

for n = 0 or 1 this loop doesn't loop since the range is [,). 
However

for BigInt:

for(i; two..n + one)

the loop starts at 0 and just keeps on going. This is clearly 
not good.


Am I having a mental breakdown or is this a real bug?


In general it feels as if BigInt needs more work as it doesn't
work with simple generic code in too many cases. Templates get
confused by invocation with a literal and a BigInt for example
when it should have a single type. Literals feel too strongly
typed or too weakly implicitly convertible.


Re: for ranges

2015-01-22 Thread Steven Schveighoffer via Digitalmars-d-learn

On 1/22/15 11:41 AM, Russel Winder via Digitalmars-d-learn wrote:

Playing with factorial implementations, as you do. I had a D
implementation using ulong. Not sensible obviously since overflow is a
bit of a problem. But the code worked, as did the tests. Now converting
to BigInt and…

The standard explicit iteration form uses a loop:

for(i; 2..n+1)

for n = 0 or 1 this loop doesn't loop since the range is [,). However
for BigInt:

for(i; two..n + one)

the loop starts at 0 and just keeps on going. This is clearly not good.

Am I having a mental breakdown or is this a real bug?




The issue:

import std.stdio;

struct S
{
int x;
int opCmp(const S other) const { writeln("compare"); return x < 
other.x ? -1 : x > other.x ? 1 : 0;}
bool opEquals(const S other) const { writeln("equals"); return x == 
other.x;}

ref S opOpAssign(string op)(int other)
{
mixin("x " ~ op ~ "= other;");
return this;
}
}

void main()
{
immutable S one = S(1);
immutable S two = S(2);
foreach(s; one..two) {}
}

output:
equals
equals

So foreach(S; one..two) translates to:

for(S x = one; x != two; x += 1)

which explains the infinite loop. I'm almost positive foreach(x; 1..2) 
uses comparison instead of equality to check for end condition.


-Steve


Re: for ranges

2015-01-22 Thread Russel Winder via Digitalmars-d-learn
On Thu, 2015-01-22 at 16:48 +, bearophile via Digitalmars-d-learn
wrote:
> > It works for me:
> 
> Sorry, you are right, it loops:

So it is a bug, and I now have to find out how to report it!

-- 
Russel.
=
Dr Russel Winder  t: +44 20 7585 2200   voip: sip:russel.win...@ekiga.net
41 Buckmaster Roadm: +44 7770 465 077   xmpp: rus...@winder.org.uk
London SW11 1EN, UK   w: www.russel.org.uk  skype: russel_winder


signature.asc
Description: This is a digitally signed message part


Re: for ranges

2015-01-22 Thread bearophile via Digitalmars-d-learn

Russel Winder:


However for BigInt:

for(i; two..n + one)

the loop starts at 0 and just keeps on going. This is clearly 
not good.


It works for me:

void main() {
import std.stdio, std.bigint;

immutable BigInt one = 1;
immutable BigInt two = 2;
uint n = 100;

foreach (immutable i; two .. n + one)
i.writeln;
}


Bye,
bearophile


Re: for ranges

2015-01-22 Thread bearophile via Digitalmars-d-learn

It works for me:


Sorry, you are right, it loops:

void main() {
import std.stdio, std.bigint;

immutable BigInt one = 1;
immutable BigInt two = 2;
uint n = 0;

foreach (immutable i; two .. n + one)
i.writeln;
}


Bye,
bearophile


for ranges

2015-01-22 Thread Russel Winder via Digitalmars-d-learn
Playing with factorial implementations, as you do. I had a D
implementation using ulong. Not sensible obviously since overflow is a
bit of a problem. But the code worked, as did the tests. Now converting
to BigInt and…

The standard explicit iteration form uses a loop:

for(i; 2..n+1)

for n = 0 or 1 this loop doesn't loop since the range is [,). However
for BigInt:

for(i; two..n + one)

the loop starts at 0 and just keeps on going. This is clearly not good.

Am I having a mental breakdown or is this a real bug?


-- 
Russel.
=
Dr Russel Winder  t: +44 20 7585 2200   voip: sip:russel.win...@ekiga.net
41 Buckmaster Roadm: +44 7770 465 077   xmpp: rus...@winder.org.uk
London SW11 1EN, UK   w: www.russel.org.uk  skype: russel_winder


signature.asc
Description: This is a digitally signed message part


Re: Defining inout returned values for ranges

2013-09-06 Thread Jonathan Crapuchettes
On Thu, 05 Sep 2013 23:32:10 +0200, anonymous wrote:

> On Thursday, 5 September 2013 at 19:19:42 UTC, Jonathan Crapuchettes
> wrote:
>> On Wed, 04 Sep 2013 11:49:41 +0200, anonymous wrote:
> [...]
>>> You can use a Template This Parameter [1] instead of inout:
>>> 
>>> auto opSlice(this This)()
>>> {
>>> static if(is(This == const)) alias QualifiedT = const
>>> T;
>>> else alias QualifiedT = T;
>>> 
>>> static struct Range {
>>> QualifiedT front() @property {
>>> 
>>> 
>>> [1] http://dlang.org/template.html#TemplateThisParameter
>>
>> Thank you for the help. That worked, but now I ran into another similar
>> issue. What if the Range struct is being defined outside of the opSlice
>> method? I have a number of methods in a struct that return the same
>> range type and would rather not have to have duplicate code or need to
>> use mixins.
>>
>> JC
> 
> Templatize Range and pass it This:
> 
> static struct Range(This)
> {
> static if(is(This == const)) alias QualifiedT = const T;
> else alias QualifiedT = T;
> 
> QualifiedT front() @property {...}
> }
> 
> auto opSlice(this This)()
> {
> return Range!This();
> }
> 
> ... more methods in the style of opSlice ...
> 
> 
> If you need QualifiedT in opSlice, make it a template over This,
> too.

Thank you again. It all appears to be working correctly.

JC


Re: Defining inout returned values for ranges

2013-09-05 Thread anonymous
On Thursday, 5 September 2013 at 19:19:42 UTC, Jonathan 
Crapuchettes wrote:

On Wed, 04 Sep 2013 11:49:41 +0200, anonymous wrote:

[...]

You can use a Template This Parameter [1] instead of inout:

auto opSlice(this This)()
{
static if(is(This == const)) alias QualifiedT = const 
T;

else alias QualifiedT = T;

static struct Range {
QualifiedT front() @property {


[1] http://dlang.org/template.html#TemplateThisParameter


Thank you for the help. That worked, but now I ran into another 
similar
issue. What if the Range struct is being defined outside of the 
opSlice
method? I have a number of methods in a struct that return the 
same range
type and would rather not have to have duplicate code or need 
to use

mixins.

JC


Templatize Range and pass it This:

   static struct Range(This)
   {
   static if(is(This == const)) alias QualifiedT = const T;
   else alias QualifiedT = T;

   QualifiedT front() @property {...}
   }

   auto opSlice(this This)()
   {
   return Range!This();
   }

   ... more methods in the style of opSlice ...


If you need QualifiedT in opSlice, make it a template over This, 
too.


Re: Defining inout returned values for ranges

2013-09-05 Thread Jonathan Crapuchettes
On Wed, 04 Sep 2013 11:49:41 +0200, anonymous wrote:

> On Wednesday, 4 September 2013 at 00:56:39 UTC, Jonathan Crapuchettes
> wrote:
>> If a range struct (Range) is defined inside another struct (Test), how
>> can the constness or mutability of Test be attributed to the return
>> type of Range.front? I'm running into this problem because I need the
>> range to be iterated, but I need the pointer in T to be marked const
>> when appropriate.
>>
>> Thank you,
>> JC
>>
>> Pseudo-Example:
>> struct Test {
>> static struct T {
>> uint* ptr;
>> }
>> ...
>>
>> auto opSlice() inout {
>> static struct Range {
>> inout(T) front() @property {
>> ...
>> }
>> ...
>> }
>>
>> return Range();
>> }
>> }
> 
> 
> You can use a Template This Parameter [1] instead of inout:
> 
> auto opSlice(this This)()
> {
> static if(is(This == const)) alias QualifiedT = const T;
> else alias QualifiedT = T;
> 
> static struct Range {
> QualifiedT front() @property {
> 
> 
> [1] http://dlang.org/template.html#TemplateThisParameter

Thank you for the help. That worked, but now I ran into another similar 
issue. What if the Range struct is being defined outside of the opSlice 
method? I have a number of methods in a struct that return the same range 
type and would rather not have to have duplicate code or need to use 
mixins.

JC


Re: Defining inout returned values for ranges

2013-09-04 Thread anonymous
On Wednesday, 4 September 2013 at 00:56:39 UTC, Jonathan 
Crapuchettes wrote:
If a range struct (Range) is defined inside another struct 
(Test), how
can the constness or mutability of Test be attributed to the 
return type
of Range.front? I'm running into this problem because I need 
the range to

be iterated, but I need the pointer in T to be marked const when
appropriate.

Thank you,
JC

Pseudo-Example:
struct Test
{
static struct T
{
uint* ptr;
}
...

auto opSlice() inout
{
static struct Range
{
inout(T) front() @property
{
...
}
...
}

return Range();
}
}



You can use a Template This Parameter [1] instead of inout:

   auto opSlice(this This)()
   {
   static if(is(This == const)) alias QualifiedT = const T;
   else alias QualifiedT = T;

   static struct Range
   {
   QualifiedT front() @property
   {


[1] http://dlang.org/template.html#TemplateThisParameter


Defining inout returned values for ranges

2013-09-03 Thread Jonathan Crapuchettes
If a range struct (Range) is defined inside another struct (Test), how 
can the constness or mutability of Test be attributed to the return type 
of Range.front? I'm running into this problem because I need the range to 
be iterated, but I need the pointer in T to be marked const when 
appropriate.

Thank you,
JC

Pseudo-Example:
struct Test
{
static struct T
{
uint* ptr;
}
...

auto opSlice() inout
{
static struct Range
{
inout(T) front() @property
{
...
}
...
}

return Range();
}
}


Re: foreach for ranges?

2012-07-18 Thread Ali Çehreli

On 07/18/2012 08:21 AM, Mike L. wrote:
>> Also, UFCS makes no sense on overloaded operators, because they 
don't get

>> called with ".", and all UFCS is is changing obj.func(params) to
>> func(obj,
>> params).
>>
>> - Jonathan M Davis
>
> Ok, that's basically what I was wondering. I had assumed foreach(e;
> someThing) {} could possibly have been converted to someThing.opApply()
> . Thanks for clarifying.

But that is still true and opApply receives the body of the foreach loop 
as a delegate:


someThing.opApply(delegate int(/* loop variables */) {
// ... the body of foreach ...
return terminationCode; // whether the user did 'break;'
});

Also, the following bug (that is already fixed) is somewhat related to 
this discussion:


  http://d.puremagic.com/issues/show_bug.cgi?id=5605

Ali



Re: foreach for ranges?

2012-07-18 Thread Mike L.
Also, UFCS makes no sense on overloaded operators, because they 
don't get
called with ".", and all UFCS is is changing obj.func(params) 
to func(obj,

params).

- Jonathan M Davis


Ok, that's basically what I was wondering. I had assumed 
foreach(e; someThing) {} could possibly have been converted to 
someThing.opApply() . Thanks for clarifying.


Re: foreach for ranges?

2012-07-17 Thread Jonathan M Davis
On Wednesday, July 18, 2012 07:19:59 Kapps wrote:
> If UFCS worked on operators, you would be able to make ranges
> without any compiler support.
> 
> int opApply(T)(T Range) if(isInputRange!T) {
>  // Stuff.
> }

You can't overload operators externally to a user-defined type. They must be 
part of the user-defined type that they operate on.

Also, UFCS makes no sense on overloaded operators, because they don't get 
called with ".", and all UFCS is is changing obj.func(params) to func(obj, 
params).

- Jonathan M Davis


Re: foreach for ranges?

2012-07-17 Thread Kapps
On Wednesday, 18 July 2012 at 04:54:51 UTC, Jonathan M Davis 
wrote:

On Wednesday, July 18, 2012 06:27:28 Mike L. wrote:
Thanks for the reply. Not sure how I missed it there. 
Interesting

that the compiler has to be made aware of a concept that I had
thought was only supposed to be part of phobos. Would it be
possible to implement it in std.range using the new UFCs?


You can do

for(; !range.empty; range.popFront())
{
auto e = range.front;
}

without the compiler doing anything at all. But if you want

for(e; range)
{}

you need a way in the language for the compiler to translate 
that into the
above. UFCS has nothing to do with it. All UFCS does is take 
a.b(c, d) and

make it b(a, c, d).

- Jonathan M Davi


If UFCS worked on operators, you would be able to make ranges 
without any compiler support.


int opApply(T)(T Range) if(isInputRange!T) {
// Stuff.
}


Re: foreach for ranges?

2012-07-17 Thread Jonathan M Davis
On Wednesday, July 18, 2012 06:27:28 Mike L. wrote:
> Thanks for the reply. Not sure how I missed it there. Interesting
> that the compiler has to be made aware of a concept that I had
> thought was only supposed to be part of phobos. Would it be
> possible to implement it in std.range using the new UFCs?

You can do

for(; !range.empty; range.popFront())
{
auto e = range.front;
}

without the compiler doing anything at all. But if you want

for(e; range)
{}

you need a way in the language for the compiler to translate that into the 
above. UFCS has nothing to do with it. All UFCS does is take a.b(c, d) and 
make it b(a, c, d).

- Jonathan M Davi


Re: foreach for ranges?

2012-07-17 Thread Mike L.
Thanks for the reply. Not sure how I missed it there. Interesting 
that the compiler has to be made aware of a concept that I had 
thought was only supposed to be part of phobos. Would it be 
possible to implement it in std.range using the new UFCs?


On Tuesday, 17 July 2012 at 19:17:47 UTC, Ali Çehreli wrote:

On 07/17/2012 11:59 AM, Mike L. wrote:
How exactly does the compiler know how to do foreach on ranges 
(for
example, ones returned by std.algorithm.map ?) I've looked 
around in

std.algorithm and std.range, but can't seem to figure it out.


The spec mentions it under 'Foreach over Structs and Classes 
with Ranges':


  http://dlang.org/statement.html#ForeachStatement

There are two methods:

a) opApply() member functions (and opApplyReverse(), which is 
rumored to be deprecated in the future)


b) empty, front, and popFront() member functions

Ali





Re: foreach for ranges?

2012-07-17 Thread Eyyub

On Tuesday, 17 July 2012 at 19:45:45 UTC, Jonathan M Davis wrote:


This post gives the current precedence, but there was some 
discussion of

adjusting it a bit:

http://forum.dlang.org/post/mailman.275.1342019430.31962.digitalmars-
d...@puremagic.com

From the looks of it, opApply gets precedence right now. But 
mixing ranges and
opApply isn't a good idea in most cases, so it doesn't come up 
very often.


- Jonathan M Davis


Ok, thanks !



Re: foreach for ranges?

2012-07-17 Thread Jonathan M Davis
On Tuesday, July 17, 2012 21:38:51 Eyyub wrote:
> On Tuesday, 17 July 2012 at 19:27:54 UTC, Jonathan M Davis wrote:
> > It translates
> > 
> > foreach(e; range)
> > {}
> > 
> > into something like
> > 
> > foreach(auto __range = range; !__range.empty;
> > __range.popFront())
> > {
> > 
> > auto e = __range.front;
> > 
> > }
> > 
> > The compiler knows just enough about ranges to enable foreach,
> > but beyond
> > that, ranges are entirely a library construct.
> 
> The spec' says "If the foreach range properties do not exist, the
> opApply method will be used instead.", does this mean that range
> properties take precedence over opApply ?

This post gives the current precedence, but there was some discussion of 
adjusting it a bit:

http://forum.dlang.org/post/mailman.275.1342019430.31962.digitalmars-
d...@puremagic.com

>From the looks of it, opApply gets precedence right now. But mixing ranges and 
opApply isn't a good idea in most cases, so it doesn't come up very often.

- Jonathan M Davis


Re: foreach for ranges?

2012-07-17 Thread Eyyub

On Tuesday, 17 July 2012 at 19:27:54 UTC, Jonathan M Davis wrote:


It translates

foreach(e; range)
{}

into something like

foreach(auto __range = range; !__range.empty; 
__range.popFront())

{
auto e = __range.front;
}

The compiler knows just enough about ranges to enable foreach, 
but beyond

that, ranges are entirely a library construct.


The spec' says "If the foreach range properties do not exist, the 
opApply method will be used instead.", does this mean that range 
properties take precedence over opApply ?




Re: foreach for ranges?

2012-07-17 Thread Jonathan M Davis
On Tuesday, July 17, 2012 20:59:12 Mike L. wrote:
> How exactly does the compiler know how to do foreach on ranges
> (for example, ones returned by std.algorithm.map ?) I've looked
> around in std.algorithm and std.range, but can't seem to figure
> it out.

It translates

foreach(e; range)
{}

into something like

foreach(auto __range = range; !__range.empty; __range.popFront())
{
auto e = __range.front;
}

The compiler knows just enough about ranges to enable foreach, but beyond 
that, ranges are entirely a library construct.

- Jonathan M Davis


Re: foreach for ranges?

2012-07-17 Thread Ali Çehreli

On 07/17/2012 11:59 AM, Mike L. wrote:

How exactly does the compiler know how to do foreach on ranges (for
example, ones returned by std.algorithm.map ?) I've looked around in
std.algorithm and std.range, but can't seem to figure it out.


The spec mentions it under 'Foreach over Structs and Classes with Ranges':

  http://dlang.org/statement.html#ForeachStatement

There are two methods:

a) opApply() member functions (and opApplyReverse(), which is rumored to 
be deprecated in the future)


b) empty, front, and popFront() member functions

Ali

--
D Programming Language Tutorial: http://ddili.org/ders/d.en/index.html


foreach for ranges?

2012-07-17 Thread Mike L.
How exactly does the compiler know how to do foreach on ranges 
(for example, ones returned by std.algorithm.map ?) I've looked 
around in std.algorithm and std.range, but can't seem to figure 
it out.


Re: higher-order funcs for ranges (with usual interface)

2011-02-07 Thread spir

On 02/07/2011 01:07 PM, Torarin wrote:

If you want to use an interface as a concept, you can take kenji's
adaptTo module and add this:

template conformsTo(T, Interfaces...)
{
  enum conformsTo = AdaptTo!Interfaces.hasRequiredMethods!T;
}

and use it like this

void draw(T)(T shape) if (conformsTo!(T, Shape, Drawable))

This will of course only work for methods, not properties or aliases,
so you still need constraints in some cases.


That's nice, thank you.

Denis
--
_
vita es estrany
spir.wikidot.com



Re: higher-order funcs for ranges (with usual interface)

2011-02-07 Thread Torarin
If you want to use an interface as a concept, you can take kenji's
adaptTo module and add this:

template conformsTo(T, Interfaces...)
{
 enum conformsTo = AdaptTo!Interfaces.hasRequiredMethods!T;
}

and use it like this

void draw(T)(T shape) if (conformsTo!(T, Shape, Drawable))

This will of course only work for methods, not properties or aliases,
so you still need constraints in some cases.

Torarin


Re: higher-order funcs for ranges (with usual interface)

2011-02-07 Thread spir

On 02/07/2011 09:18 AM, Lars T. Kyllingstad wrote:

I cannot stand the "is()" idiom/syntax ;-) Dunno why. Would happily
>>>  get rid of it in favor of type-classes (built eg as an extension to
>>>  current interfaces). For instance, instead of:
>>>
>>> void func (T) (T t)
>>> if (is(someConstraint1)&&   is(someConstraint2))
>>> {
>>> ...
>>> }
>>>
>>>  use:
>>>
>>> void func (SomeTypeClass T) (T t)
>>> {
>>> ...
>>> }
>>>
>>>  For instance (untested):
>>>
>>> void func (T) (T t)
>>> if (isInputRange(T)&&   is(ElementType!T == E))
>>>  -->
>>> void func (InputRange!E T) (T t)
>>>
>>>  where InputRange is a (templated) interface / type-class.
>>>
>>>  Type-class checks on/type/  /template/  parameters (as opposed to type
>>>  checks on regular value parameters) would be performed structurally
>>>  (as opposed to nominally). D knows how to do this, since that's what
>>>  it needs to perform when checking is() constraints.

>>
>>  I agree that is() is rather ugly.  Same with __traits.  If you haven't
>>  already done so, I suggest you vote up this issue:
>>
>>  http://d.puremagic.com/issues/show_bug.cgi?id=3702

>
>  Done!
>  (I did not get all the details 'cause no time for a deep look, but
>  anything impulsed by the motivation of getting rid of is() and __traits
>  can hardly be a Bad Thing ;-)
>
>  What do you think of type classes, as an alternative to Don's proposal
>  in issue #3702.
>  See also "Type Classes as Objects and Implicits":
>  http://ropas.snu.ac.kr/~bruno/papers/TypeClasses.pdf
>

>>  Anyway, you can hide is()'s ugliness in the most common cases, though,
>>  by defining new templates.  For instance, I wouldn't mind having the
>>  following in std.range as an overload of isInputRange:
>>
>>  template isInputRange(R, T)
>>  {
>>  enum isInputRange = isInputRange!R&&   is(ElementType!R == T);
>>  }
>>
>>  Then, you'd simply write
>>
>>  void func(R)(R range) if (isInputRange!(R, E)) { ... }
>>
>>  -Lars

>
>  A great improvement, indeed.
>
>  While we're at defining a set of constraints in a template, let us make
>  it an interface / type-class that the E must (structurally) satisfy, and
>  just write:
>void func(InputRange!E R)(R range) { ... }
>
>  What do you think?
>
>  Note: a template is not always required, I guess:
>void writeElements (Iterable Elements) (Elements elements) {
>foreach (element, elements) {
>write(element,' ');
>}
>}
>  (In this case, because write is itself generic.)


How would you deal with the case where the input must satisfy more than
one concept/constraint?  I mean, for the simple case where you say "R
must be an input range of E", sure, type classes/concepts are cleaner.
But what about the case where, say, you want R to be an infinite random
access range that supports slicing?  With template constraints it's
simple:

 void doStuff(R)(R someRange)
 if (isRandomAccessRange!R&&  isInfinite!R&&  hasSlicing!R)
 {
 ...
 }

Now, I'm no expert on concepts at all---my main sources of information
about them are superficial comments on the D newsgroup and a quick browse
of the Wikipedia page---but it seems to me that you'd have to define a
new concept for each such combination of constraints.  Or?


Well, dunno really. If a language implements type classes, let us see how 
things work there :-)


Note that above, you use 3 implicite type-class defining check funcs. Agreed? 
Certainly, because they are common, one wrote a fucn to wrap a bigger set of 
is() stuff. Replacing them with a type-class interface allows
(1) reusing an interface for what it's meant: defining a (super) type, instead 
of a func which is appropriate and does /not/ correctly convey the meaning

(2) avoiding is()

Now, you may be right in that type-class check may need be written externally:

void doStuff(R)(R someRange)
  if (RandomAccessRange R && InfiniteRange R &&  Slicable R)

or not:

interface ASpecialOne : RandomAccessRange, InfiniteRange, Slicable {}
void doStuff (ASpecialOneR) (R someRange)

Ain't that clean? For sure, if I was to define a new static PL, I would go 
/that/ way for generic constraints.
This remembers me about another option maybe: when I have time, I'll go and see 
how XL does it. If (you do not know XL, then /really/ have a look when you have 
time: http://en.wikipedia.org/wiki/XL_%28programming_language%29 ;esp explore 
the notion of "conceptual programming")


Denis
--
_
vita es estrany
spir.wikidot.com



Re: higher-order funcs for ranges (with usual interface)

2011-02-07 Thread Lars T. Kyllingstad
On Thu, 03 Feb 2011 19:11:04 +0100, spir wrote:

> On 02/03/2011 02:25 PM, Lars T. Kyllingstad wrote:
>> On Thu, 03 Feb 2011 13:53:44 +0100, spir wrote:
>>
>>> On 02/03/2011 01:17 PM, Lars T. Kyllingstad wrote:
 Why the reluctance to use template constraints?  They're so flexible!
 :)
>>>
>>> I cannot stand the "is()" idiom/syntax ;-) Dunno why. Would happily
>>> get rid of it in favor of type-classes (built eg as an extension to
>>> current interfaces). For instance, instead of:
>>>
>>>   void func (T) (T t)
>>>   if (is(someConstraint1)&&  is(someConstraint2))
>>>   {
>>>   ...
>>>   }
>>>
>>> use:
>>>
>>>   void func (SomeTypeClass T) (T t)
>>>   {
>>>   ...
>>>   }
>>>
>>> For instance (untested):
>>>
>>>   void func (T) (T t)
>>>   if (isInputRange(T)&&  is(ElementType!T == E))
>>> -->
>>>   void func (InputRange!E T) (T t)
>>>
>>> where InputRange is a (templated) interface / type-class.
>>>
>>> Type-class checks on /type/ /template/ parameters (as opposed to type
>>> checks on regular value parameters) would be performed structurally
>>> (as opposed to nominally). D knows how to do this, since that's what
>>> it needs to perform when checking is() constraints.
>>
>> I agree that is() is rather ugly.  Same with __traits.  If you haven't
>> already done so, I suggest you vote up this issue:
>>
>>http://d.puremagic.com/issues/show_bug.cgi?id=3702
> 
> Done!
> (I did not get all the details 'cause no time for a deep look, but
> anything impulsed by the motivation of getting rid of is() and __traits
> can hardly be a Bad Thing ;-)
> 
> What do you think of type classes, as an alternative to Don's proposal
> in issue #3702.
> See also "Type Classes as Objects and Implicits":
> http://ropas.snu.ac.kr/~bruno/papers/TypeClasses.pdf
> 
>> Anyway, you can hide is()'s ugliness in the most common cases, though,
>> by defining new templates.  For instance, I wouldn't mind having the
>> following in std.range as an overload of isInputRange:
>>
>>template isInputRange(R, T)
>>{
>>enum isInputRange = isInputRange!R&&  is(ElementType!R == T);
>>}
>>
>> Then, you'd simply write
>>
>>void func(R)(R range) if (isInputRange!(R, E)) { ... }
>>
>> -Lars
> 
> A great improvement, indeed.
> 
> While we're at defining a set of constraints in a template, let us make
> it an interface / type-class that the E must (structurally) satisfy, and
> just write:
>  void func(InputRange!E R)(R range) { ... }
> 
> What do you think?
> 
> Note: a template is not always required, I guess:
>  void writeElements (Iterable Elements) (Elements elements) {
>   foreach (element, elements) {
>  write(element,' ');
>  }
>  }
> (In this case, because write is itself generic.)


How would you deal with the case where the input must satisfy more than 
one concept/constraint?  I mean, for the simple case where you say "R 
must be an input range of E", sure, type classes/concepts are cleaner.  
But what about the case where, say, you want R to be an infinite random 
access range that supports slicing?  With template constraints it's 
simple:

void doStuff(R)(R someRange)
if (isRandomAccessRange!R && isInfinite!R && hasSlicing!R)
{
...
}

Now, I'm no expert on concepts at all---my main sources of information 
about them are superficial comments on the D newsgroup and a quick browse 
of the Wikipedia page---but it seems to me that you'd have to define a 
new concept for each such combination of constraints.  Or?

-Lars


Re: higher-order funcs for ranges (with usual interface)

2011-02-03 Thread spir

On 02/03/2011 02:25 PM, Lars T. Kyllingstad wrote:

On Thu, 03 Feb 2011 13:53:44 +0100, spir wrote:


On 02/03/2011 01:17 PM, Lars T. Kyllingstad wrote:

Why the reluctance to use template constraints?  They're so flexible!
:)


I cannot stand the "is()" idiom/syntax ;-) Dunno why. Would happily get
rid of it in favor of type-classes (built eg as an extension to current
interfaces). For instance, instead of:

  void func (T) (T t)
  if (is(someConstraint1)&&  is(someConstraint2))
  {
  ...
  }

use:

  void func (SomeTypeClass T) (T t)
  {
  ...
  }

For instance (untested):

  void func (T) (T t)
  if (isInputRange(T)&&  is(ElementType!T == E))
-->
  void func (InputRange!E T) (T t)

where InputRange is a (templated) interface / type-class.

Type-class checks on /type/ /template/ parameters (as opposed to type
checks on regular value parameters) would be performed structurally (as
opposed to nominally). D knows how to do this, since that's what it
needs to perform when checking is() constraints.


I agree that is() is rather ugly.  Same with __traits.  If you haven't
already done so, I suggest you vote up this issue:

   http://d.puremagic.com/issues/show_bug.cgi?id=3702


Done!
(I did not get all the details 'cause no time for a deep look, but anything 
impulsed by the motivation of getting rid of is() and __traits can hardly be a 
Bad Thing ;-)


What do you think of type classes, as an alternative to Don's proposal in issue 
#3702.

See also "Type Classes as Objects and Implicits":
http://ropas.snu.ac.kr/~bruno/papers/TypeClasses.pdf


Anyway, you can hide is()'s ugliness in the most common cases, though, by
defining new templates.  For instance, I wouldn't mind having the
following in std.range as an overload of isInputRange:

   template isInputRange(R, T)
   {
   enum isInputRange = isInputRange!R&&  is(ElementType!R == T);
   }

Then, you'd simply write

   void func(R)(R range) if (isInputRange!(R, E)) { ... }

-Lars


A great improvement, indeed.

While we're at defining a set of constraints in a template, let us make it an 
interface / type-class that the E must (structurally) satisfy, and just write:

void func(InputRange!E R)(R range) { ... }

What do you think?

Note: a template is not always required, I guess:
void writeElements (Iterable Elements) (Elements elements) {
foreach (element, elements) {
write(element,' ');
}
}
(In this case, because write is itself generic.)

Denis
--
_
vita es estrany
spir.wikidot.com



Re: higher-order funcs for ranges (with usual interface)

2011-02-03 Thread Lars T. Kyllingstad
On Thu, 03 Feb 2011 13:53:44 +0100, spir wrote:

> On 02/03/2011 01:17 PM, Lars T. Kyllingstad wrote:
>> Why the reluctance to use template constraints?  They're so flexible!
>> :)
> 
> I cannot stand the "is()" idiom/syntax ;-) Dunno why. Would happily get
> rid of it in favor of type-classes (built eg as an extension to current
> interfaces). For instance, instead of:
> 
>  void func (T) (T t)
>  if (is(someConstraint1) && is(someConstraint2))
>  {
>  ...
>  }
> 
> use:
> 
>  void func (SomeTypeClass T) (T t)
>  {
>  ...
>  }
> 
> For instance (untested):
> 
>  void func (T) (T t)
>  if (isInputRange(T) && is(ElementType!T == E))
> -->
>  void func (InputRange!E T) (T t)
> 
> where InputRange is a (templated) interface / type-class.
> 
> Type-class checks on /type/ /template/ parameters (as opposed to type
> checks on regular value parameters) would be performed structurally (as
> opposed to nominally). D knows how to do this, since that's what it
> needs to perform when checking is() constraints.

I agree that is() is rather ugly.  Same with __traits.  If you haven't 
already done so, I suggest you vote up this issue:

  http://d.puremagic.com/issues/show_bug.cgi?id=3702

Anyway, you can hide is()'s ugliness in the most common cases, though, by 
defining new templates.  For instance, I wouldn't mind having the 
following in std.range as an overload of isInputRange:

  template isInputRange(R, T)
  {
  enum isInputRange = isInputRange!R && is(ElementType!R == T);
  }

Then, you'd simply write

  void func(R)(R range) if (isInputRange!(R, E)) { ... }

-Lars


Re: higher-order funcs for ranges (with usual interface)

2011-02-03 Thread spir

On 02/03/2011 01:17 PM, Lars T. Kyllingstad wrote:

Why the reluctance to use template constraints?  They're so flexible! :)


I cannot stand the "is()" idiom/syntax ;-) Dunno why. Would happily get rid of 
it in favor of type-classes (built eg as an extension to current interfaces). 
For instance, instead of:


void func (T) (T t)
if (is(someConstraint1) && is(someConstraint2))
{
...
}

use:

void func (SomeTypeClass T) (T t)
{
...
}

For instance (untested):

void func (T) (T t)
if (isInputRange(T) && is(ElementType!T == E))
-->
void func (InputRange!E T) (T t)

where InputRange is a (templated) interface / type-class.

Type-class checks on /type/ /template/ parameters (as opposed to type checks on 
regular value parameters) would be performed structurally (as opposed to 
nominally). D knows how to do this, since that's what it needs to perform when 
checking is() constraints.


Denis
--
_
vita es estrany
spir.wikidot.com



Re: higher-order funcs for ranges (with usual interface)

2011-02-03 Thread Lars T. Kyllingstad
On Thu, 03 Feb 2011 13:05:00 +0100, spir wrote:

> On 02/03/2011 08:41 AM, Lars T. Kyllingstad wrote:
>> On Wed, 02 Feb 2011 18:38:02 +0100, spir wrote:
> 
>>> I guess the only solution would be for the compiler to support a kind
>>> of reange type syntax?
>>
>> I'm not sure I understand what you mean here.  Perhaps you're looking
>> for something like concepts, which have been discussed for both D and
>> C++0x but rejected in both languages:
>>
>>  http://en.wikipedia.org/wiki/Concept_%28generic_programming%29
> 
> Yes, I know about concepts ;-) (and typestates, and such). That's not
> what I mean but I could not find how to express it. What I have in mind
> is a way to simply express  just like  is
> expressed by "T[]". But indeed the issue is there is only one type of
> array of T, while there are an infinity of types of ranges of T.
> Your solution below is a good alternative.
> 
>> Anyway, if the source and target range are of the same (known) kind,
>> something like this should work:
>>
>>  struct MyRange(T) { ... }
>>
>>  MyRange!Out map(In, Out)(MyRange!In input, Out delegate(In) f) {
>>  ...
>>  }
>>
>> If they are of different kinds, but still known, this should work:
>>
>>  struct MySourceRange(T) { ... }
>>  struct MyTargetRange(T) { ... }
>>
>>  MyTargetRange!Out map(In, Out)
>>  (MySourceRange!In input, Out delegate(In) f)
>>  {
>>  ...
>>  }
>>
>> Note that I am only talking about what the compiler should be able to
>> figure out through IFTI (implicit function template instantiation), and
>> not about actual implementation.
> 
> Right, this is more or less what I was looking for. And I think I can
> restrict cases to ranges beeing of the same "kind". If necessary, the
> result can then be mapped onto another kind of range (hopefully lazily).
> The only "un-workaround-able" situation is, I guess, when the source
> range is infinite ;-)

Why the reluctance to use template constraints?  They're so flexible! :)

-Lars


Re: higher-order funcs for ranges (with usual interface)

2011-02-03 Thread spir

On 02/03/2011 08:41 AM, Lars T. Kyllingstad wrote:

On Wed, 02 Feb 2011 18:38:02 +0100, spir wrote:



I guess the only solution would be for the compiler to support a kind of
reange type syntax?


I'm not sure I understand what you mean here.  Perhaps you're looking for
something like concepts, which have been discussed for both D and C++0x
but rejected in both languages:

 http://en.wikipedia.org/wiki/Concept_%28generic_programming%29


Yes, I know about concepts ;-) (and typestates, and such). That's not what I 
mean but I could not find how to express it. What I have in mind is a way to 
simply express  just like  is expressed by "T[]". But 
indeed the issue is there is only one type of array of T, while there are an 
infinity of types of ranges of T.

Your solution below is a good alternative.


Anyway, if the source and target range are of the same (known) kind,
something like this should work:

 struct MyRange(T) { ... }

 MyRange!Out map(In, Out)(MyRange!In input, Out delegate(In) f)
 {
 ...
 }

If they are of different kinds, but still known, this should work:

 struct MySourceRange(T) { ... }
 struct MyTargetRange(T) { ... }

 MyTargetRange!Out map(In, Out)
 (MySourceRange!In input, Out delegate(In) f)
 {
 ...
 }

Note that I am only talking about what the compiler should be able to
figure out through IFTI (implicit function template instantiation), and
not about actual implementation.


Right, this is more or less what I was looking for. And I think I can restrict 
cases to ranges beeing of the same "kind". If necessary, the result can then be 
mapped onto another kind of range (hopefully lazily).
The only "un-workaround-able" situation is, I guess, when the source range is 
infinite ;-)



Denis
--
_
vita es estrany
spir.wikidot.com



Re: higher-order funcs for ranges (with usual interface)

2011-02-02 Thread Lars T. Kyllingstad
On Wed, 02 Feb 2011 18:38:02 +0100, spir wrote:

> On 02/02/2011 02:18 PM, Lars T. Kyllingstad wrote:
>> On Wed, 02 Feb 2011 13:26:39 +0100, spir wrote:
>>
>>> Hello,
>>>
>>> This bit of code for arrays:
>>>
>>> Out[] map (In,Out) (In[] input, Out delegate (In) f) {
>>>   Out[] output = new Out[](input.length); foreach (i,item ; input)
>>>   output [i] = f(item);
>>>   return output;
>>> }
>>> unittest {
>>>   char character (uint code) {return cast(char)code;} uint[] codes
>>>   = [0x61,0x62,0x63];
>>>   // functional style
>>>   writeln(map(codes,&character));    // "abc" // OO style
>>>   writeln(codes.map(&character)); // "abc"
>>> }
>>>
>>> How to write this for ranges? [...]
>>>
>>> For ranges, I'm looking for something similar to:
>>>   Range!Out map (In,Out) (Range!In input, Out delegate (In) f)
>>>   {...}
>>> Indeed, the compiler should understand that Range!T is a type id just
>>> like T[].
>>
>> I don't think it's possible to do it exactly as you describe.  I mean,
>> Range in that case can be anything, and you can't always return a range
>> of the same kind.
> 
> Right. The output range's ElementType is given by f's return type. As
> you say, the "kind" of range may change. Even if it's the same, how
> could one express that: ,
> syntactically and in the param set, just like
>  is written "T[]"? Currently, we must
> (1) declare the range type as template param, which is a bit redondant
> because the ElementType must also be given, (2) add some 'is' horror
> code:
>   if (isInputRange!Range && is(ElementType!Range : In))
> I guess the only solution would be for the compiler to support a kind of
> reange type syntax?

I'm not sure I understand what you mean here.  Perhaps you're looking for 
something like concepts, which have been discussed for both D and C++0x 
but rejected in both languages:

http://en.wikipedia.org/wiki/Concept_%28generic_programming%29


Anyway, if the source and target range are of the same (known) kind, 
something like this should work:

struct MyRange(T) { ... }

MyRange!Out map(In, Out)(MyRange!In input, Out delegate(In) f)
{
...
}

If they are of different kinds, but still known, this should work:

struct MySourceRange(T) { ... }
struct MyTargetRange(T) { ... }

MyTargetRange!Out map(In, Out)
(MySourceRange!In input, Out delegate(In) f)
{
...
}

Note that I am only talking about what the compiler should be able to 
figure out through IFTI (implicit function template instantiation), and 
not about actual implementation.


>>   Two possibilities are, you can do it eagerly,
>>
>>Out[] map(Range, In, Out)(Range input, Out delegate(In) f)
>>if (isInputRange!Range&&  is(ElementType!Range : In))
>>{
>>...
>>}
> 
> OK.
> 
>> or you can do it lazily by defining your own map range (untested):
>>
>>struct Map(Range, In, Out)
>>if (isInputRange!Range&&  is(ElementType!Range : In)
>>{
>>Range input;
>>Out delegate(In) f;
>>
>>@property bool empty() { return input.empty; }
>>
>>// Inefficient, should cache front... @property Out front() {
>>return f(input.front); }
>>
>>void popFront() { input.popFront(); }
>>}
> 
> That's similar to what I did.
> 
>>Map!(Range, Out) map(Range, In, Out)(Range input, Out delegate(In)
>>f)
>>if (isInputRange!R&&  is(ElementType!Range : In)
>>{
>>return typeof(return)(input, f);
>>}
> 
> What's the point of map, then? My version initially had a 'MapRange'
> defined as static struct template inside map, but then map just
> instanciated it, so I suppressed map alltogether, letting the user
> write:
>   auto r2 = MapRange!(R1, In, Out)(input, f);
> which is not more complicated than calling the func, I guess.

map() is just a helper function.   Unlike struct literals/constructors, 
functions can make use of IFTI, which makes for much prettier code:

// The range from my example, without map()
auto result =
Map!(SomeRange!int, int, bool)(someRange, someDelegate);

// The range from my example, with map()
auto result = map(someInputRange, someDelegate);

This has become a quite common idiom in Phobos.  std.range, for instance, 
is littered with helper functions like this:

  Retro, retro()
  Stride, stride()
  Chain, chain()
  ...

The list goes on.

-Lars


Re: higher-order funcs for ranges (with usual interface)

2011-02-02 Thread spir

On 02/02/2011 02:18 PM, Lars T. Kyllingstad wrote:

On Wed, 02 Feb 2011 13:26:39 +0100, spir wrote:


Hello,

This bit of code for arrays:

Out[] map (In,Out) (In[] input, Out delegate (In) f) {
  Out[] output = new Out[](input.length); foreach (i,item ; input)
  output [i] = f(item);
  return output;
}
unittest {
  char character (uint code) {return cast(char)code;} uint[] codes =
  [0x61,0x62,0x63];
  // functional style
  writeln(map(codes,&character));// "abc" // OO style
  writeln(codes.map(&character)); // "abc"
}

How to write this for ranges? [...]

For ranges, I'm looking for something similar to:
  Range!Out map (In,Out) (Range!In input, Out delegate (In) f) {...}
Indeed, the compiler should understand that Range!T is a type id just
like T[].


I don't think it's possible to do it exactly as you describe.  I mean,
Range in that case can be anything, and you can't always return a range
of the same kind.


Right. The output range's ElementType is given by f's return type. As you say, 
the "kind" of range may change. Even if it's the same, how could one express 
that: , syntactically and in the param set, 
just like  is written "T[]"?
Currently, we must (1) declare the range type as template param, which is a bit 
redondant because the ElementType must also be given, (2) add some 'is' horror 
code:

 if (isInputRange!Range && is(ElementType!Range : In))
I guess the only solution would be for the compiler to support a kind of reange 
type syntax?



  Two possibilities are, you can do it eagerly,

   Out[] map(Range, In, Out)(Range input, Out delegate(In) f)
   if (isInputRange!Range&&  is(ElementType!Range : In))
   {
   ...
   }


OK.


or you can do it lazily by defining your own map range (untested):

   struct Map(Range, In, Out)
   if (isInputRange!Range&&  is(ElementType!Range : In)
   {
   Range input;
   Out delegate(In) f;

   @property bool empty() { return input.empty; }

   // Inefficient, should cache front...
   @property Out front() { return f(input.front); }

   void popFront() { input.popFront(); }
   }


That's similar to what I did.


   Map!(Range, Out) map(Range, In, Out)(Range input, Out delegate(In) f)
   if (isInputRange!R&&  is(ElementType!Range : In)
   {
   return typeof(return)(input, f);
   }


What's the point of map, then? My version initially had a 'MapRange' defined as 
static struct template inside map, but then map just instanciated it, so I 
suppressed map alltogether, letting the user write:

auto r2 = MapRange!(R1, In, Out)(input, f);
which is not more complicated than calling the func, I guess.


-Lars


Denis
--
_
vita es estrany
spir.wikidot.com



Re: higher-order funcs for ranges (with usual interface)

2011-02-02 Thread Lars T. Kyllingstad
On Wed, 02 Feb 2011 13:26:39 +0100, spir wrote:

> Hello,
> 
> This bit of code for arrays:
> 
> Out[] map (In,Out) (In[] input, Out delegate (In) f) {
>  Out[] output = new Out[](input.length); foreach (i,item ; input)
>  output [i] = f(item);
>  return output;
> }
> unittest {
>  char character (uint code) {return cast(char)code;} uint[] codes =
>  [0x61,0x62,0x63];
>  // functional style
>  writeln(map(codes, &character));// "abc" // OO style
>  writeln(codes.map(&character));     // "abc"
> }
> 
> How to write this for ranges? [...]
>
> For ranges, I'm looking for something similar to:
>  Range!Out map (In,Out) (Range!In input, Out delegate (In) f) {...}
> Indeed, the compiler should understand that Range!T is a type id just
> like T[].

I don't think it's possible to do it exactly as you describe.  I mean, 
Range in that case can be anything, and you can't always return a range 
of the same kind.  Two possibilities are, you can do it eagerly,

  Out[] map(Range, In, Out)(Range input, Out delegate(In) f)
  if (isInputRange!Range && is(ElementType!Range : In))
  {
  ...
  }

or you can do it lazily by defining your own map range (untested):

  struct Map(Range, In, Out)
  if (isInputRange!Range && is(ElementType!Range : In)
  {
  Range input;
  Out delegate(In) f;

  @property bool empty() { return input.empty; }

  // Inefficient, should cache front...
  @property Out front() { return f(input.front); }
  
  void popFront() { input.popFront(); }
  }

  Map!(Range, Out) map(Range, In, Out)(Range input, Out delegate(In) f)
  if (isInputRange!R && is(ElementType!Range : In)
  {
  return typeof(return)(input, f);
  }

-Lars


Re: higher-order funcs for ranges (with usual interface)

2011-02-02 Thread Lars T. Kyllingstad
On Wed, 02 Feb 2011 13:18:07 +, Lars T. Kyllingstad wrote:

> [...]
> 
>   struct Map(Range, In, Out)
>   if (isInputRange!Range && is(ElementType!Range : In)
>   {
>   Range input;
>   Out delegate(In) f;
> 
>   @property bool empty() { return input.empty; }
> 
>   // Inefficient, should cache front... @property Out front() {
>   return f(input.front); }
>   
>   void popFront() { input.popFront(); }
>   }
> 
>   Map!(Range, Out) map(Range, In, Out)(Range input, Out delegate(In) f)
>   if (isInputRange!R && is(ElementType!Range : In)
>   {
>   return typeof(return)(input, f);
>   }

Oops, seems i missed a few closing parentheses on the template 
constraints.

-Lars


higher-order funcs for ranges (with usual interface)

2011-02-02 Thread spir

Hello,

This bit of code for arrays:

Out[] map (In,Out) (In[] input, Out delegate (In) f) {
Out[] output = new Out[](input.length);
foreach (i,item ; input)
output [i] = f(item);
return output;
}
unittest {
char character (uint code) {return cast(char)code;}
uint[] codes = [0x61,0x62,0x63];
// functional style
writeln(map(codes, &character));// "abc"
// OO style
writeln(codes.map(&character)); // "abc"
}

How to write this for ranges? I mean, with the same kind of interface to client 
code (not the interface of std.algo.map).
And is there a way to write it so that it works both for ranges and other kinds 
of sequences (arrays, strings); or even for anything "iterable" (AA, set, list, 
tree...).


For ranges, I'm looking for something similar to:
Range!Out map (In,Out) (Range!In input, Out delegate (In) f) {...}
Indeed, the compiler should understand that Range!T is a type id just like T[].

Denis
--
_
vita es estrany
spir.wikidot.com