Re: Using map result type

2019-12-11 Thread Meta via Digitalmars-d-learn

On Wednesday, 11 December 2019 at 20:08:37 UTC, Meta wrote:

import std.algorithm;
import std.range;

void mapAccepter(E)(InputRange!E r)
{
import std.array: array;
import std.stdio: writeln;

auto collected = r.array;
writeln(collected);
}

void main()
{
int[] nums = [1, 2, 3];
auto evenness = inputRangeObject(map!(n => n % 2 == 
0)(nums));

mapAccepter(evenness);
}


I guess I should mention, that if you are expecting a range of 
booleans, you can of course write  mapAccepter as a non-templated 
function:


void mapAccepter(InputRange!bool r);

But if you want to support any type of input range, the function 
needs to at least be templated on the element type of the range.


Re: Using map result type

2019-12-11 Thread Meta via Digitalmars-d-learn

On Sunday, 8 December 2019 at 01:10:21 UTC, AA wrote:
I'd like to accept the return type of map. From some previous 
questions that I should accept a template?

So for something like:

```
void mapAccepter(Range)(Range r)
{
import std.array : array;
import std.stdio : writeln;

auto collected = r.array;
writeln(collected);
}

void main()
{
import std.algorithm.iteration : map;

int[] nums = [1, 2, 3];
auto evenness = map!(n => n % 2 == 0)(nums);
mapAccepter(evenness);
}
```


1) Is there any way I can make `mapAccepter` not a templated 
function?


Yes (mostly, anyway), using the interfaces in 
std.range.interfaces:

https://dlang.org/phobos/std_range_interfaces.html

import std.algorithm;
import std.range;

void mapAccepter(E)(InputRange!E r)
{
import std.array: array;
import std.stdio: writeln;

auto collected = r.array;
writeln(collected);
}

void main()
{
int[] nums = [1, 2, 3];
auto evenness = inputRangeObject(map!(n => n % 2 == 0)(nums));
mapAccepter(evenness);
}

`mapAccepter` still needs to be templated on the element type of 
the range,
but there are ways to avoid that as well, if desired. I wouldn't 
recommend it,

however, as it wouldn't be that useful in this case.

2) Is there any way if I need to make `mapAccepter` templated 
to constrain Range to be a range of booleans.


Yup, there are two ways that you you primarily do that. Either
constraining E in the template declaration, or adding a constraint
on the template. Generally option 2 is the more idiomatic D way.

Option 1: constrain E to be of type bool:
void mapAccepter(E: bool)(InputRange!E r);

OR

void mapAccepter(E)(InputRange!E r)
if (is(E == bool));

There's not much difference between these two, but the latter is 
probably preferred.


Option 2: use std.traits and a template constraint:
void mapAccepter(E)(InputRange!E r)
if (is(ElementType!r == bool));



Re: Using map result type

2019-12-10 Thread Dominikus Dittes Scherkl via Digitalmars-d-learn

On Tuesday, 10 December 2019 at 07:23:56 UTC, AA wrote:

Would the second solution of declaring a template constraint 
like that be considering strange/out of place in D? e.g. do 
people normally try and declare the template constraints on a 
function or just rely on compile time failure from to 
instantiate template.


No, you can do "normal" OOP as you like. But you will encounter 
the constraint approach often in phobos and other libraries, as 
is provides some advantages.


Re: Using map result type

2019-12-09 Thread AA via Digitalmars-d-learn

On Sunday, 8 December 2019 at 01:43:43 UTC, mipri wrote:

On Sunday, 8 December 2019 at 01:10:21 UTC, AA wrote:

[...]


In general this is what you want to do with any kind of range
code, because you're not working with definite types, but with
types that have certain properties. And an advantage of this is
that you can decide to do more or less efficient things at
compile time based on additional properties of the types you're
working with. Just open up phobos and look for 'static if':

https://github.com/dlang/phobos/blob/master/std/algorithm/searching.d#L3858

So if you you give minPos an array, it'll just foreach() over
the array and return a slice. In which case minPos is exactly
as efficient as the code you would've written by hand instead
of using minPos, because it expands to that same code.

And if you give minPos something else, it'll still work.


[...]



[...]


Not really. Even if you try to use typeof() to get the
(internal) type that std.alogorithm.map returns, you'll run
into errors like

Error: function x253.mapAccepter(MapResult!(__lambda5, int[]) 
r) is not callable using argument types (MapResult!(__lambda1, 
int[]))


when you try to use it.


[...]


Certainly. Static reflection's what this kind of generic code
is all about. See all the constraints in the std.algorithm pages
in the library documentation?  Just look at this one, randomly
picked:
https://dlang.org/phobos/std_algorithm_searching.html#.endsWith

  if (isBidirectionalRange!Range
  && (Needles.length > 1)
  && is(typeof(.endsWith!pred(doesThisEnd, 
withOneOfThese[0])) : bool)
  && is(typeof(.endsWith!pred(doesThisEnd, 
withOneOfThese[1..$])) : uint));


So for your code:

  void mapAccepter(Range)(Range r)
  if (is(ElementType!Range == bool))
  {
  import std.array : array;
  import std.stdio : writeln;

  auto collected = r.array;
  writeln(collected);
  }

Or if you do this often, maybe something like this would do:

  enum RangeOfBools(T) = is(ElementType!T == bool) && 
isInputRange!T;


  void mapAccepter(Range)(Range r) if (RangeOfBools!Range)
  {
  import std.array : array;
  import std.stdio : writeln;

  auto collected = r.array;
  writeln(collected);
  }


Thanks for the detailed reply. So maybe it is just my perspective 
coming from other languages that I was expecting a class i.e. 
having some interface based way of dealing with the return type. 
But I guess isInputRange checks for structural equality rather 
than class and doesn't encode that into any interfaces in std 
library normally?


Would the second solution of declaring a template constraint like 
that be considering strange/out of place in D? e.g. do people 
normally try and declare the template constraints on a function 
or just rely on compile time failure from to instantiate template.


Re: Using map result type

2019-12-07 Thread mipri via Digitalmars-d-learn

On Sunday, 8 December 2019 at 01:10:21 UTC, AA wrote:

I'd like to accept the return type of map. From some previous
questions that I should accept a template?


In general this is what you want to do with any kind of range
code, because you're not working with definite types, but with
types that have certain properties. And an advantage of this is
that you can decide to do more or less efficient things at
compile time based on additional properties of the types you're
working with. Just open up phobos and look for 'static if':

https://github.com/dlang/phobos/blob/master/std/algorithm/searching.d#L3858

So if you you give minPos an array, it'll just foreach() over
the array and return a slice. In which case minPos is exactly
as efficient as the code you would've written by hand instead
of using minPos, because it expands to that same code.

And if you give minPos something else, it'll still work.


So for something like:

```
void mapAccepter(Range)(Range r)
{
import std.array : array;
import std.stdio : writeln;

auto collected = r.array;
writeln(collected);
}

void main()
{
import std.algorithm.iteration : map;

int[] nums = [1, 2, 3];
auto evenness = map!(n => n % 2 == 0)(nums);
mapAccepter(evenness);
}
```



1) Is there any way I can make `mapAccepter` not a templated
function?


Not really. Even if you try to use typeof() to get the
(internal) type that std.alogorithm.map returns, you'll run
into errors like

Error: function x253.mapAccepter(MapResult!(__lambda5, int[]) r) 
is not callable using argument types (MapResult!(__lambda1, 
int[]))


when you try to use it.


2) Is there any way if I need to make `mapAccepter` templated
to constrain Range to be a range of booleans.


Certainly. Static reflection's what this kind of generic code
is all about. See all the constraints in the std.algorithm pages
in the library documentation?  Just look at this one, randomly
picked:
https://dlang.org/phobos/std_algorithm_searching.html#.endsWith

  if (isBidirectionalRange!Range
  && (Needles.length > 1)
  && is(typeof(.endsWith!pred(doesThisEnd, 
withOneOfThese[0])) : bool)
  && is(typeof(.endsWith!pred(doesThisEnd, 
withOneOfThese[1..$])) : uint));


So for your code:

  void mapAccepter(Range)(Range r)
  if (is(ElementType!Range == bool))
  {
  import std.array : array;
  import std.stdio : writeln;

  auto collected = r.array;
  writeln(collected);
  }

Or if you do this often, maybe something like this would do:

  enum RangeOfBools(T) = is(ElementType!T == bool) && 
isInputRange!T;


  void mapAccepter(Range)(Range r) if (RangeOfBools!Range)
  {
  import std.array : array;
  import std.stdio : writeln;

  auto collected = r.array;
  writeln(collected);
  }



Using map result type

2019-12-07 Thread AA via Digitalmars-d-learn
I'd like to accept the return type of map. From some previous 
questions that I should accept a template?

So for something like:

```
void mapAccepter(Range)(Range r)
{
import std.array : array;
import std.stdio : writeln;

auto collected = r.array;
writeln(collected);
}

void main()
{
import std.algorithm.iteration : map;

int[] nums = [1, 2, 3];
auto evenness = map!(n => n % 2 == 0)(nums);
mapAccepter(evenness);
}
```

1) Is there any way I can make `mapAccepter` not a templated 
function?
2) Is there any way if I need to make `mapAccepter` templated to 
constrain Range to be a range of booleans.