List comprehensions for D
Quirin Schroll
qs.il.paperinik at gmail.com
Mon Jun 10 14:44:42 UTC 2024
### Intro
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.
### Design
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.
### Simple Example
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) { … }
```
### Grammar
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)*
### Semantics
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()`.
More information about the dip.ideas
mailing list