www.digitalmars.com         C & C++   DMDScript  

digitalmars.dip.ideas - List comprehensions for D



Many languages, especially high-level and functional ones, have 
list comprehensions. Translated to D lingo, one can get a range 
object with elements based on other ranges. The hardest thing for 
D is to come up with a reasonable syntax and semantics.

Comprehensions have two main advantages:
* They are more readable than filter and map operations.
* They are more concise than filter and map operations.



Generally speaking, a comprehension has two parts: destinations 
and sources/conditions/variables.

So, the basic template is this:
```d
[ ArgumentList ; Comprehensors ]
```
The argument list usually has 1 entry, but it can have more.

The `Comprehensors` are what I called 
sources/conditions/variables. They are semicolon-separated and 
every `Comprehensor` is of the form of a `foreach` (for a 
source), an `if` (for a condition), or a variable declaration.



A simple example of a filter:
```d
foreach (x; [ x; foreach (x; xs); if (x > 0) ]) { … }
```
The bracketed thing is a first-class object and has a type 
(unspelled, like a lambda), so it can be e.g. assigned to a local 
variable.
```d
auto positives = [ x; foreach (x; xs); if (x > 0) ];
foreach (x; positives) { … }
```


Without links:
```
ComprehensionExpression:
     [ ArgumentList ; Comprehensors ]
Comprehensors:
     Comprehensor ;?
     Comprehensor ; Comprehensors?
Comprehensor:
     AggregateForeach
     RangeForeach
     if ( IfCondition )
     VarDeclarations
```
With Links:
*`ComprehensionExpression`*:
    `[` 
*[`ArgumentList`](https://dlang.org/spec/grammar.html#ArgumentList)* `;`
*`Comprehensors`* `]`
*`Comprehensors`*:
    *`Comprehensor`* `;`?
    *`Comprehensor`* `;` *`Comprehensors`*?
*`Comprehensor`*:
    *[`AggregateForeach`](https://dlang.org/spec/grammar.html#AggregateForeach)*
    *[`RangeForeach`](https://dlang.org/spec/grammar.html#RangeForeach)*
    `if` `(` 
*[`IfCondition`](https://dlang.org/spec/grammar.html#IfCondition)* `)`
    *[`VarDeclarations`](https://dlang.org/spec/grammar.html#VarDeclarations)*



This is implemented by a lowering. A ComprehensionExpression is 
an object of the following type:
```d
struct CE // name is exposition-only and an implementation 
defined name
{
     int opApplyImpl(DG)(scope DG dg) // name is exposition-only 
and an implementation defined name
     {
         // Comprehensors
         if (auto result = dg(ArgumentList)) return result;
         return 0;
     }
     alias opApply = opApplyImpl!(int delegate(
         typeof(ArgumentList) // (see comment below)
     ));
}
```
For arguments that are lvalues, a `ref` is included unless the 
argument is a non-`ref` local variable (or foreach variable) 
declared in the comprehension expression.

The `ComprehensionExpression` is replaced by `CE()`.
Jun 10