2010-11-06 11 views
7

Este código invierte una cadena:¿Puedo usar el operador de canalización en F # para pasar un argumento a un constructor?

let reverse (s : string) = new string(s.ToCharArray() |> Array.rev) 

puede esto ser reescrito usando el operador de canalización para pasar el argumento necesario para la string() constructor? Por ejemplo, esto parece más idiomática:

// Doesn't compile: 
let reverse (s : string) = s.ToCharArray() |> Array.rev |> new string 

Del mismo modo, ¿por qué no puedo utilizar el operador string de la siguiente manera?

let reverse2 (s : string) = s.ToCharArray() |> Array.rev |> string 

Aquí está en acción:

> reverse2 "foo" ;; 
val it : string = "System.Char[]" 

Devuelve el tipo en lugar de "Fuera de la oficina".

+0

posible duplicado de [Uso del símbolo de tubería F # con un constructor de objetos] (http://stackoverflow.com/questions/531178/using-the-f-pipe-symbol-with-an-object-constructor) – gradbot

+0

This debería ser posible en F # 4.0 cuando salga: http://blogs.msdn.com/b/fsharpteam/archive/2014/11/12/announcing-a-preview-of-f-4-0-and-the -visual-f-tools-in-vs-2015.aspx –

Respuesta

9

No, el operador de tuberías solo se puede usar con funciones F #, no se puede usar con constructores de clases, métodos miembros o métodos estáticos. La razón es que la sobrecarga soportada por este tipo de métodos complicaría la inferencia del tipo F #. Sin embargo, si realmente desea utilizar tuberías, se puede asignar cada elemento de la matriz de caracteres a una tubería de cadena y luego esa secuencia en Seq.concat "":

s.ToCharArray() |> Array.rev |> Seq.map(string) |> String.concat "" 

O usted podría envolver la llamada cadena de constructor en un método F #:

let stringCArrCtor (carr: char[]) = 
    new string(carr) 

s.ToCharArray() |> Array.rev |> stringCArrCtor 

Y para responder a su última pregunta,

s.ToCharArray() |> Array.rev |> string 

no se pueden utilizar debido a que es equivalente a

(s.ToCharArray() |> Array.rev).ToString() 

y el método Array ToString() no se reemplaza, por lo que solo devuelve el nombre de tipo reflejado predeterminado.

+0

Gracias por su respuesta. Al observar la firma de tipo del operador 'string', ¿cómo supo que no era solo una función que tomaba un objeto y devolvía una cadena? Todavía estoy atascado en mi última pregunta. – royco

+1

@Slack, si pasa el mouse sobre la función de cadena, le dirá que es una función 'T -> string' que 'convierte el argumento en una cadena usando ToString()'. También puede ver que es parte del espacio de nombres Operadores, donde junto con otras funciones de conversión (como int, long, float, ...), obtiene un tratamiento especial por parte del compilador para que funcionen como funciones optimizadas "sobrecargadas". . Vea las líneas 4074-4091 en prim-types.fs en el código fuente. –

9

Como mencionó Stephen, lo mejor que se puede hacer es definir una nueva función que llame al constructor. Puede colocarlo en un módulo llamado String (en algunos su espacio de nombres), por lo que tendrá una sensación similar a la de otras funciones F #. Probablemente me volvería a usar:

module String = 
    let create (c:char[]) = new string(c) 

La cuestión del uso de constructores como valores de primera clase apareció en SO antes, pero no puedo encontrar mi respuesta anterior más - hay un truco muy loco que le da la capacidad, pero es un hack enorme (nadie debería usarlo nunca y alguna próxima versión de F # no lo permitirá). De todos modos, puede utilizar statically resolved type parameters a escribir lo siguiente:

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

Y el uso de la función de la siguiente manera:

"ABC".ToCharArray() |> Array.rev |> ctor<string, _>;; 

La función ctor esencialmente requiere que el tipo especificado como primer parámetro tipo tiene un constructor y llama al constructor (el otro parámetro de tipo es el argumento del constructor y el compilador lo infiere). Pero esto es solo una curiosidad: definir tu propia función es el mejor enfoque.

+0

Eso es genial. Debo comenzar a aprender F # correctamente ahora! – leppie

+0

Extraño, ese "truco" rompe fsi.exe 3.1 con: error FS3066: Nombre de miembro inválido. Los miembros pueden no tener el nombre '.ctor' o '.cctor' – larsw

Cuestiones relacionadas