2010-02-28 28 views
12

¿cómo se convierte de una lista de caracteres a una cadena?Convierta una lista de caracteres (o matriz) en una cadena

Para decirlo de otra manera, ¿cómo revertir List.ofSeq "abcd"?

ACTUALIZACIÓN: new System.String (List.ofSeq "abcd" |> List.toArray) |> printfn "%A" parece funcionar bien, con o sin new, pero List.ofSeq "abcd" |> List.toArray) |> new System.String |> printfn "%A" falla. ¿Por qué?

Respuesta

20

Pregunté a similar question una vez antes. Parece que los constructores de objetos no son compostables, por lo que no puedes pasarlos como una función.

List.ofSeq "abcd" |> List.toArray |> (fun s -> System.String s) |> printfn "%A" 
List.ofSeq "abcd" |> List.toArray |> (fun s -> new System.String(s)) |> printfn "%A" 

actualización constructores son funciones de primera clase como de F # 4,0

List.ofSeq "abcd" |> List.toArray |> System.String |> printfn "%A" 
+0

bien, esta limitación tiene sentido en cuanto al rendimiento (la creación de un lambda que es probablemente difícil de optimizar el rendimiento de distancia, probablemente puede hacer daño en la manera que es difícil detectar). Cualquier puntero sobre por qué 'nuevo' es opcional? ¿Hacer que la creación de objetos por reflexión se combine mejor con la sintaxis Ocaml/F #? ¡Gracias! –

+0

Algo difícil de elegir una de las respuestas, elegiré esta porque hace referencia a otra pregunta relacionada. :-) –

+0

"Parece que los constructores de objetos no se pueden componer, por lo que no se pueden pasar como una función". Esto finalmente está cambiando. https://github.com/fsharp/FSharpLangDesign/blob/master/FSharp-4.0/ClassNamesAsFunctionsDesignAndSpec.md – Endrju

4

Su enfoque:

new System.String (listOfChars |> List.toArray) 

es la solución por lo general terminan con demasiados.

El sistema de inferencia de gramática/tipo de F # simplemente parece incapaz de reconocer un constructor de .NET como new String como una función curried (que evita el uso de pipelining).

10

Trabajo con cadenas en F # A veces es un poco incómodo. Probablemente usaría el mismo código que Dario. La gramática F # no permite el uso de constructores como funciones de primera clase, por lo que lamentablemente no se puede hacer todo el procesamiento en una sola canalización. En general, puede usar miembros estáticos y métodos de instancia como funciones de primera clase, pero no propiedades de instancia o constructores.

De todos modos, hay un truco realmente desagradable que puedes usar para convertir un constructor en un valor de función. No recomendaría de utilizarlo, pero yo estaba bastante sorprendido de ver que realmente funciona, así que pensé que puede valer la pena compartirlo:

let inline ctor< ^R, ^T 
    when ^R : (static member ``.ctor`` : ^T -> ^R)> (arg:^T) = 
    (^R : (static member ``.ctor`` : ^T -> ^R) arg) 

Esto define una función que se coloca en línea durante el tiempo de compilación, el cual requiere que el primer parámetro de tipo tenga un constructor que tome un valor del segundo parámetro de tipo. Esto se especifica como una restricción de tiempo de compilación (porque los genéricos .NET no pueden expresar esto). Además, F # no le permite especificar esto usando la sintaxis habitual para especificar restricciones de constructor (que debe tomar unit como argumento), pero puede usar el nombre compilado de los constructores. Ahora se puede escribir por ejemplo:

// just like 'new System.Random(10)' 
let rnd = ctor<System.Random, _> 10 
rnd.Next(10) 

Y también se puede utilizar el resultado de ctor como la función de primera clase:

let chars = [ 'a'; 'b'; 'c' ] 
let str = chars |> Array.ofSeq |> ctor<System.String, _> 

Como ya he dicho, creo que esto es principalmente una curiosidad, sino una muy interesante :-).

+0

+1: coolness !!! – Juliet

0

Sólo se enfrentó a problemas similares, y se acercó con estas soluciones:

List.fold (fun str x -> str + x.ToString()) "" (List.ofSeq "abcd") 
Cuestiones relacionadas