September 09, 2015 Re: What is "FilterResult" type? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bahman Movaqar | On Wednesday, 9 September 2015 at 07:19:06 UTC, Bahman Movaqar wrote:
> On Tuesday, 8 September 2015 at 18:45:33 UTC, Jonathan M Davis wrote:
>> [...]
>
> @Jonathan, @cym13 and @Meta
> It's reasonable to use `auto`. However there are times when you need to pass the `auto` value to another function and the receiving function needs to know the type of its input arguments.
>
> In other news:
> Consider the following piece of code. *Please note that I am aware that the simple problem introduced can be solved in several ways which are more efficient.*
>
> immutable struct FooBar {
> int x;
> int y;
> }
> immutable(FooBar)[] foobars = [
> FooBar(60, 100),
> FooBar(8, 20),
> FooBar(9, 15)
> ];
> int[] nums = [20, 40, 55];
>
> //////////////////////////////////////////
> // find FooBars which:
> // - x * y is greater than any `num`
> // - x and y are smaller than any `num`
> //////////////////////////////////////////
> auto result = reduce!(
> (acc, num) => acc.filter!(
> fb => (fb.x < num && fb.y < num) && (fb.x * fb.y > num)
> )
> )(foobars, nums);
> //
> assert(result[0].x == 9 && result[0].y == 15);
>
> This fails to compile with the following message:
>
> Error: static assert "Incompatible function/seed/element: test.__unittestL40_4.__lambda1/immutable(FooBar)[]/int"
> /usr/include/dmd/phobos/std/algorithm/iteration.d(2518):
> instantiated from here: reduceImpl!(false, int[], immutable(FooBar)[])
> /usr/include/dmd/phobos/std/algorithm/iteration.d(2502):
> instantiated from here: reducePreImpl!(int[], immutable(FooBar)[]) test.d(56): instantiated from here: reduce!(immutable(FooBar)[], int[])
>
> The only way to make it work is `.array.idup` the output of `filter`. For example:
>
> auto result = reduce!(
> (acc, num) => acc.filter!(
> fb => (fb.x < num && fb.y < num) && (fb.x * fb.y > num)
> ).array.idup
> )(foobars, nums);
>
> Honestly, I cannot comprehend anything out of this; why I had to realise the lazy value and `idup` it for it to become usable by `reduce`?
> Does this mean that I am simply missing something obvious?
You are using reduce in a weird way here... I find it normal to have to use weird internal tricks if you are trying weird things. The way I would have written it is:
auto result = foobars.filter!(fb => nums.all!(n => (fb.x * fb.y) > n))
.filter!(fb => nums.all!(n => fb.x < n && fb.y < n));
Here you don't have any weird and completely unreadable reduce construct and don't have to realize the lazy check as std.algorithm.searching.all is lazy too.
|
September 09, 2015 Re: What is "FilterResult" type? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bahman Movaqar | On Wednesday, 9 September 2015 at 07:19:06 UTC, Bahman Movaqar wrote:
> On Tuesday, 8 September 2015 at 18:45:33 UTC, Jonathan M Davis wrote:
>> If you're returning a range, you should be returning auto.
>
> @Jonathan, @cym13 and @Meta
> It's reasonable to use `auto`. However there are times when you need to pass the `auto` value to another function and the receiving function needs to know the type of its input arguments.
No, it doesn't. It needs to know what the compile-time interface is, i.e. what it can do with that type. If the type in question happens to be an InputRange, then the consumer function would be:
void func(R)(R range) if(isInputRange!R) { ... }
instead of using a concrete type like this:
void func(MyType range) { ... }
That way you can change range types and `func` doesn't care.
Atila
|
September 09, 2015 Re: What is "FilterResult" type? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Atila Neves | On Wednesday, 9 September 2015 at 09:08:28 UTC, Atila Neves wrote:
> No, it doesn't. It needs to know what the compile-time interface is, i.e. what it can do with that type. If the type in question happens to be an InputRange, then the consumer function would be:
>
> void func(R)(R range) if(isInputRange!R) { ... }
>
> instead of using a concrete type like this:
>
> void func(MyType range) { ... }
>
> That way you can change range types and `func` doesn't care.
Ah...makes sense. Thanks.
|
September 09, 2015 Re: What is "FilterResult" type? | ||||
---|---|---|---|---|
| ||||
Posted in reply to cym13 | On Wednesday, 9 September 2015 at 08:29:20 UTC, cym13 wrote: > You are using reduce in a weird way here... Oh? Perhaps it was all because of the lame example I used :-) The real problem I was trying to solve, source of which I just pushed[1], was the `select` method on line 130. Is this idiomatic or still weird? > The way I would have written it is: > > auto result = foobars.filter!(fb => nums.all!(n => (fb.x * fb.y) > n)) > .filter!(fb => nums.all!(n => fb.x < n && fb.y < n)); For the lame example I gave, something similar occurred to me at first; but then I thought 4 `filter`s (assuming `all` is simply a `filter`) might be non-idiomatic as it might incur some performance penalty. > Here you don't have any weird and completely unreadable reduce construct and don't have to realize the lazy check as std.algorithm.searching.all is lazy too. True. But is pumping the output of `filter` as the seed into `reduce` really considered weird usage!? [1] https://github.com/bahmanm/d-etudes/blob/master/source/e002/models.d |
September 09, 2015 Re: What is "FilterResult" type? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bahman Movaqar | On Wednesday, 9 September 2015 at 11:30:26 UTC, Bahman Movaqar wrote: > For the lame example I gave, something similar occurred to me at first; but then I thought 4 `filter`s (assuming `all` is simply a `filter`) might be non-idiomatic as it might incur some performance penalty. As those are templates I don't think you'd have any overhead ; I may be wrong about that but the whole point of such constructs is to allow what Walter poetically called “memory disallocation”. https://www.youtube.com/watch?v=znjesAXEEqw > True. But is pumping the output of `filter` as the seed into `reduce` really considered weird usage!? I don't think it is really weird per se, I just can't think of a case where there isn't a better way to do it. I find it completely unreadable frankly, and I generally avoid reduce when I can because it is not UFCS-able. This is only personal opinion though. |
September 09, 2015 Re: What is "FilterResult" type? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bahman Movaqar | On Wednesday, 9 September 2015 at 11:30:26 UTC, Bahman Movaqar wrote:
> On Wednesday, 9 September 2015 at 08:29:20 UTC, cym13 wrote:
>> The way I would have written it is:
>>
>> auto result = foobars.filter!(fb => nums.all!(n => (fb.x * fb.y) > n))
>> .filter!(fb => nums.all!(n => fb.x < n && fb.y < n));
>
> For the lame example I gave, something similar occurred to me at first; but then I thought 4 `filter`s (assuming `all` is simply a `filter`) might be non-idiomatic as it might incur some performance penalty.
Note that this can easily be rewritten with only one `filter` and one `all`:
auto result = foobars.filter!(
fb => nums.all!(
n => fb.x * fb.y > n
&& fb.x < n
&& fb.y < n));
|
September 11, 2015 Re: What is "FilterResult" type? | ||||
---|---|---|---|---|
| ||||
Posted in reply to cym13 | On Wednesday, 9 September 2015 at 13:16:49 UTC, cym13 wrote:
>> True. But is pumping the output of `filter` as the seed into `reduce` really considered weird usage!?
>
> I don't think it is really weird per se, I just can't think of a case where there isn't a better way to do it. I find it completely unreadable frankly, and I generally avoid reduce when I can because it is not UFCS-able. This is only personal opinion though.
Now I see your point. I too find fold/reduce the least transparent verb of the list comprehension. And certainly your point about UFCS adds to it.
|
Copyright © 1999-2021 by the D Language Foundation