D2: std.algorithm.indexOf doesn't work anymore
I posted the following code on rosettacode.org for the task of converting Arabic and Roman numerals.
import std.regex, std.array, std.algorithm;
immutable {
int[] weights = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
string[] symbols = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX",
"V", "IV", "I"];
}
string toRoman(int n) {
auto app = appender!string;
foreach (i, w; weights) {
while (n >= w) {
app.put(symbols[i]);
n -= w;
}
if (n == 0) break;
}
return app.data;
}
int toArabic(string s) {
int arabic;
foreach (m; match(s, "CM|CD|XC|XL|IX|IV|[MDCLXVI]")) {
arabic += weights[symbols.indexOf(m.hit)];
}
return arabic;
}
It used to work just fine, but now I get a compiler error.
Error: template std.algorithm.indexOf(alias pred = "a == b",R1,R2) if (is(typeof(startsWith!(pred)(haystack,needl e)))) does not match any function template declaration
According to the documentation indexOf is deprecated, and countUntil sho开发者_如何转开发uld be used in stead, but it gives me the same error.
Long story but I'll try to keep it short:
std.algorithm.indexOf
expects an input range, which is a structural type that must define front
, popFront()
and empty
. For arrays, these methods are defined in std.array and work via uniform function call syntax, which allows fun(someArray)
to work the same as someArray.fun()
.
immutable string[]
is not an input range, since popFront
removes the first element of the array, which cannot be done for an immutable type. The fact that this used to work was a bug.
I've updated the Rosetta Code entry to change symbols
to an immutable(string)[]
. Here, the elements of symbols
are immutable, but the array may be sliced and reassigned. For example:
void main() {
immutable string[] s1 = ["a", "b", "c"];
immutable(string)[] s2 = ["d", "e", "f"];
s2 = s2[1..$]; // This is what std.array.popFront does under the hood.
assert(s2 == ["e", "f"]); // Passes.
s2[1] = "g"; // Error: Can't modify immutable data.
s1 = s1[1..$]; // Error: Can't modify immutable data.
s1[1] = "g"; // Error: Can't modify immutable data.
}
immutable string[]
is implicitly convertible to immutable(string)[]
but implicit function template instantiation (often denoted IFTI; this is what's used to instantiate the indexOf
template) is not smart enough try this.
I believe this is a bug in std.algorithm
. If you remove the immutable
qualifier, the code works as is. I think indexOf
/countUntil
should work on immutable
arrays, but at the moment it does not.
You can make them manifest constants (precede each declaration with enum
) and it appears to work. Amusingly, this may also be a bug.
Apologies for the breakage; I introduced it. I concur with dsimcha's description and proposed fix.
We are considering a simple change to the language to account for this simple case. That would automatically peel off one level of qualifiers when passing a value of a qualified type into a function. By that (for now hypothetical) rule, qualifier(T[]) would become (when passed to a function) qualifier(T)[] and qualifier(T*) would become qualifier(T)*. This would allow your example to work. The disadvantage is that a function would not be able to distinguish the top-level qualifier but I believe that that does not harm any concrete use.
精彩评论