Skip to content

List Comprehension Syntax

Let's create arguably one of the most useful constructs when working with iterable structures: list comprehensions. This can be done thanks to Ryna's syntax definition features.

What is list comprehension?

List comprehensions are a syntax option in some languages that allow the programmer to transform the values of a list or even filter them without having to create an explicit for loop and a temporary variable. In this case, we will not deal with filtering the list.

Creating the syntax

The syntax for list comprehensions then to be something like this:

[expr for elem in container]

This is problematic for us because Ryna is a strongly typed language. We will have to adapt it like this:

[expr for elem: ElemType in container]

This can be expressed in NDL like this:

"[" 
    [s] Arg(<expr>, map) [s]                                        // Map expression
    "for" [s] Arg(<ident>, it) [s] ":" [s] Arg(<type>, type) [s]    // Element
    "in" [s] Arg(<expr>, container) [s]                             // Container
"]"

Note that you need Args to mark the variables that we will use inside the body.

Generating the body

Internally, a list comprehension is just a for loop with a transformation function. There are multiple ways to do this, but this is one of them (again, note that we have to escape the for's closing brace):

syntax list_comprehension from [...] {
    let res = arr<$type>();
    let func = ($it: $type) -> $type $map;

    for _it_ in $container {
        res.push(func(*_it_));
    \}

    return move(res);
}

Example

Making use of an Array initialization syntax, you can build the following code:

let array = [i * 2 for i: Int in <Int>[1, 2, 3, 4, 5]]; // [2, 4, 6, 8, 10]

This would compile to:

let array = do {
    let res = arr<Int>();
    let func = (i: Int) -> Int i * 2;

    for _it_ in <Int>[1, 2, 3, 4, 5] {
        res.push(func(*_it_));
    }

    return *res;
};

In this example <Int>[1, 2, 3, 4, 5] would also be recursively compiled into a new expression based on a lambda expression, but the exact compilation is not important.