2011-03-31 11 views
7

Publiqué el siguiente código en rosettacode.org para la tarea converting Arabic and Roman numerals.D2: std.algorithm.indexOf no funciona más

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; 
} 

Solía ​​funcionar bien, pero ahora me sale un error del compilador.

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

De acuerdo con la documentación indexOf es obsoleto, y countUntil debe usarse en lugar, pero me da el mismo error.

Respuesta

6

larga historia, pero voy a tratar de ser breve:

std.algorithm.indexOf espera un input range, que es un structural type que deben definir front, popFront() y empty. Para las matrices, estos métodos son defined in std.array y funcionan a través de la sintaxis de llamada de función uniforme, que permite que fun(someArray) funcione igual que someArray.fun().

immutable string[] no es un rango de entrada, ya que popFront elimina el primer elemento de la matriz, que no se puede hacer para un tipo inmutable. El hecho de que esto solía funcionar era un error.

He actualizado la entrada del Código Rosetta para cambiar symbols a immutable(string)[]. Aquí, los elementos de symbols son inmutables, pero la matriz puede cortarse y reasignarse. Por ejemplo:

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[] es convertir implícitamente a immutable(string)[] pero implícito plantilla de función de instancias (a menudo denotado Ifti; esto es lo que se utiliza para crear una instancia de la plantilla indexOf) no es lo suficientemente inteligente como tratar esto.

+0

Veo. ¿Hay alguna manera de obtener el índice de un elemento en una colección inmutable, o debo encapsular las matrices, hacerlas privadas, crear accesos y rodar mi propio índice? – fwend

+0

@fwend: en este momento, la forma más fácil es convertirlo en cabezal mutable. Por ejemplo: 'inmutable (string) [] headMutable = symbols;', luego haz lo que necesites hacer con 'headMutable' en lugar de' symbols'. – dsimcha

+0

¿Conoce alguna propuesta para solucionar esto? No poder usar 'indexOf' en una matriz inmutable es un problema bastante grande. –

4

Creo que esto es un error en std.algorithm. Si elimina el calificador immutable, el código funciona como está. I piensaindexOf/countUntil debería funcionar en matrices immutable, pero por el momento no lo hace.

Puede hacer que se manifiesten constantes (antes de cada declaración con enum) y parece que funciona. Amusingly, this may also be a bug.

+0

Comenté el bloque inmutable y funciona ahora – fwend

3

Disculpas por la rotura; Lo presenté. Estoy de acuerdo con la descripción de dsimcha y la solución propuesta.

Estamos considerando un cambio simple en el idioma para dar cuenta de este caso simple. Eso despegaría automáticamente un nivel de calificadores al pasar un valor de un tipo calificado a una función. Con esa regla (por ahora hipotética), el calificador (T []) se convertiría (cuando se pasara a una función) en calificador (T) [] y el calificador (T *) se convertiría en calificador (T) *. Esto permitiría que tu ejemplo funcione. La desventaja es que una función no podría distinguir el calificador de nivel superior, pero creo que eso no daña un uso concreto.

+0

Cómo ¿Funcionaría esto con los tipos 'class' y' struct's pasados ​​por 'ref'? No se puede despegar de un "inmutable", de lo contrario, el objeto inmutable se convierte de repente en mutable dentro de la función. Esta regla hipotética huele a pescado y suena como el tipo de cosa que causará problemas más tarde de maneras sutiles. –

+0

@Peter: Primero, hay un parche experimental escrito por Michel Fortin que introduce referencias mutables a objetos de clase inmutables. En segundo lugar, las personas tienden a almacenar matrices inmutables como, p. tablas estáticas con bastante frecuencia, pero normalmente no manipularían un rango general inmutable. Dicho esto, acepto una regla más general sería deseable. –