This code reverses a string:
let reverse (s : string) = new string(s.ToCharArray() |> Array.rev)
Can this be rewritten using the pipeline operator to pass the required argument to the string()
constructor? For example, this seems more idiomatic:
// Doesn't compile:
let reverse (s : string) = s.ToCharArray() |> Array.rev |> new string
Similarly, why can't I use the string
operator in the following way?
let reverse2 (s : string) = s.ToCharArray() |> Array.rev |> string
Here it is in action:
> reverse2 "foo" ;;
val it : string = "System.Char[]"
It returns the type rather than "oof".
As Stephen mentioned, the best thing to do is to define a new function that calls the constructor. You can place it into a module named
String
(in some your namespace), so you'll get similar feeling as when working with other F# functions. I would probably use:The question of using constructors as first-class values appeared on SO before, but I cannot find my earlier answer anymore - there is one very crazy trick that gives you the ability, but it is an enormous hack (nobody should ever use it and some next version of F# is hopefuly going to disallow that). Anyway, you can use statically resolved type parameters to write the following:
And use the function like this:
The
ctor
function essentially requires that the type specified as the first type parameter has a constructor and it calls the constructor (the other type parameter is the argument to the constructor and is inferred by the compiler). But this is really just a curiosity - defining your own function is the best approach.No, the pipe operator may only be used with F# functions, it cannot be used with class constructors, member methods or static methods. The reason being that the overloading supported by these kinds of methods would complicate F#'s type inference. However, if you really want to use piping, you could map each element of the char Array to a String and then pipe that sequence into
Seq.concat ""
:Or you could wrap the string constructor call in an F# method:
And to answer your last question,
can't be used because it is equivalent to
and the Array ToString() method is not overridden so it just returns the default reflected type name.