Thread overview
Pass range to a function
Jul 27, 2017
Chris
Jul 27, 2017
Ali Çehreli
Jul 28, 2017
Seb
Jul 29, 2017
Meta
July 27, 2017
I'm using regex `matchAll`, and mapping it to get a sequence of strings. I then want to pass that sequence to a function. What is the general "sequence of strings" type declaration I'd need to use?

In C#, it'd be `IEnumerable<string>`. I'd rather not do a to-array on the sequence, if possible. (e.g. It'd be nice to just pass the lazy sequence into my categorize function.)

What is the value of `???` in the following program:


```
import std.stdio, std.regex, std.string, std.algorithm.iteration;

auto regexToStrSeq(RegexMatch!string toks) {
  return toks.map!(t => t[0].strip());
}

void categorize(??? toks) {
  foreach (t; toks) {
    writeln(t);
  }
}

void main()
{
    auto reg = regex("[\\s,]*(~@|[\\[\\]{\\}()'`~^@]|\"(?:\\\\.|[^\\\\\"])*\"|;.*|[^\\s\\[\\]{}('\"`,;)]*)");
    auto line = "(+ 1 (* 2 32))";
    auto baz = matchAll(line, reg);

    categorize(regexToStrSeq(baz).array);
}
```
July 27, 2017
On 07/27/2017 02:16 PM, Chris wrote:

> What is the value of `???` in the following program:

> void categorize(??? toks) {
>   foreach (t; toks) {
>     writeln(t);
>   }
> }

The easiest solution is to make it a template (R is a suitable template variable name for a range type):

void categorize(R)(R toks) {
  foreach (t; toks) {
    writeln(t);
  }
}

Your function will work with any type that can be iterated with foreach and can be passed to writeln. However, you can use template constraints to limit its usage, document its usage, or produce better compilation errors when it's called with an incompatible type (the error message would point at the call site as opposed to the body of categorize):

import std.range;
import std.traits;

void categorize(R)(R toks)
if (isInputRange!R && isSomeString!(ElementType!R)) {
  foreach (t; toks) {
    writeln(t);
  }
}

Ali

July 28, 2017
On Thursday, 27 July 2017 at 21:16:03 UTC, Chris wrote:
> In C#, it'd be `IEnumerable<string>`. I'd rather not do a to-array on the sequence, if possible. (e.g. It'd be nice to just pass the lazy sequence into my categorize function.)

This comparison between Linq and D ranges might help you in the future too:

https://github.com/wilzbach/linq
July 29, 2017
On Thursday, 27 July 2017 at 21:16:03 UTC, Chris wrote:
> I'm using regex `matchAll`, and mapping it to get a sequence of strings. I then want to pass that sequence to a function. What is the general "sequence of strings" type declaration I'd need to use?
>
> In C#, it'd be `IEnumerable<string>`. I'd rather not do a to-array on the sequence, if possible. (e.g. It'd be nice to just pass the lazy sequence into my categorize function.)
>
> What is the value of `???` in the following program:
>
>
> ```
> import std.stdio, std.regex, std.string, std.algorithm.iteration;
>
> auto regexToStrSeq(RegexMatch!string toks) {
>   return toks.map!(t => t[0].strip());
> }
>
> void categorize(??? toks) {
>   foreach (t; toks) {
>     writeln(t);
>   }
> }
>
> void main()
> {
>     auto reg = regex("[\\s,]*(~@|[\\[\\]{\\}()'`~^@]|\"(?:\\\\.|[^\\\\\"])*\"|;.*|[^\\s\\[\\]{}('\"`,;)]*)");
>     auto line = "(+ 1 (* 2 32))";
>     auto baz = matchAll(line, reg);
>
>     categorize(regexToStrSeq(baz).array);
> }
> ```

If for some reason you can't make categorize a template like Ali suggested, or you need runtime polymorphism, you can use std.range.interfaces:

import std.range.interfaces;

void categorize(InputRange!string toks)
{
    foreach (t; toks) {
        writeln(t);
    }
}

void main()
{
    //etc.
    categorize(inputRangeObject(regexToStrSeq(baz)));
}