Filter and Map's weird return types cause frustration...
Allen Nelson
ithinkican at gmail.com
Sat Feb 23 00:48:24 PST 2013
I'm trying to do some functional programming techniques on lists
in D, and while I'm happy that there's some functionality to be
found, some of (what I perceive as) the language's foibles don't
make it as smooth as I'd like. Here's an example:
import std.stdio, std.algorithm;
void main() {
string[][] example = [["a", "b", "sdflk"],
["sdflkjsd", "sdl"],
["sdfjhsdklfjh", "sdkjfh", "alskaslk"]];
writeln(example);
int i=2;
bool isLongEnough (string[] slist) {return slist.length > i;}
example = filter!(isLongEnough)(example);
writeln(example);
}
It seems a perfectly valid desire, to have an array and want to
prune it down into an array that satisfies certain requirements.
After all, this is exactly what filter is supposed to do. This
code seems fairly straightforward then, but trying to compile it:
> dmd test.d
test.d(10): Error: cannot implicitly convert expression
(filter(reps)) of type FilterResult!(isLongEnough, string[][]) to
string[][]
So essentially, the compiler is telling me that even though
filter's whole raison d'etre is to take a data structure and
return the same kind of data structure, but with some values
possibly removed, it not only returns a weird in-house-brand
"FilterResult" type, it can't even convert this into a into a
string[][] type. Now, I could use "auto" instead of "string[][]",
and it works, but I have no use for a "FilterResult". I don't
know what methods I can call on it, or what it's made out of. I
want a string[][].
A similar story happens with the map function. Map takes an array
and a function and returns another array which is of values
computed from applying the function to the input array. One would
think, then that this code would work:
void main() {
string[][] reps = [["a", "b", "sdflk"],
["sdflkjsd", "sdl"],
["sdfjhsdklfjh", "sdkjfh", "alskaslk"]];
writeln(reps);
int[] lengths = map!("a.length")(reps);
writeln(lengths);
}
After all, the .length function returns an int, and we have an
array of them, so map returns an int, right? Wrong!
dmd test.d
test.d(8): Error: cannot implicitly convert expression
(map(reps)) of type MapResult!(unaryFun, string[][]) to int[]
Once again, even though the returned array is, for all intents
and purposes, an int[], I can't call it that. Which means I can't
concatenate onto an existing int[], for example.
Why are filter and map returning these weird one-off types in the
first place? Why would filter return anything but the same type
of list that it was passed as an argument? Why would map return
anything other than an array of whatever type matches the return
value of the operator? And if there's some good reason why these
things are the case, why then at the very least would you not be
able to easily cast the return type into the return type that you
want?
More information about the Digitalmars-d
mailing list