Convert a list of characters (or array) to a string

14,703

Solution 1

I asked a similar question once before. It seems object constructors aren't composable so you can't pass them as a function.

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"

Update Constructors are first-class functions as of F# 4.0

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

Solution 2

Working with strings in F# is sometimes a bit uncomfortable. I would probably use the same code as Dario. The F# grammar doesn't allow using constructors as first class functions, so you unfortunately cannot do the whole processing in a single pipeline. In general, you can use static members and instance methods as first class functions, but not instance properties or constructors.

Anyway, there is a really nasty trick you can use to turn a constructor into a function value. I would not recommend actually using it, but I was quite surprised to see that it actually works, so I thought it may be worth sharing it:

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

This defines a function that will be inlined at compile time, which requires that the first type parameter has a constructor that takes a value of the second type parameter. This is specified as a compile-time constraint (because .NET generics cannot express this). Also, F# doesn't allow you to specify this using the usual syntax for specifying constructor constraints (which must take unit as the argument), but you can use the compiled name of constructors. Now you can write for example:

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

And you can also use the result of ctor as first-class function:

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

As I said, I think this is mainly a curiosity, but a pretty interesting one :-).

Solution 3

Your approach:

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

is the solution I usually end up with too.

F#'s grammar/type inference system simply seems unable to recognize a .NET constructor like new String as a curried function (which prevents you from using pipelining).

Solution 4

Just faced similar problem, and came up with this solutions:

List.fold (fun str x -> str + x.ToString()) "" (List.ofSeq "abcd") 
Share:
14,703

Related videos on Youtube

Miron Brezuleanu
Author by

Miron Brezuleanu

More about me at mbrezu.me

Updated on February 19, 2020

Comments

  • Miron Brezuleanu
    Miron Brezuleanu about 4 years

    how does one convert from a list of characters to a string?

    To put it another way, how do I reverse List.ofSeq "abcd"?

    UPDATE: new System.String (List.ofSeq "abcd" |> List.toArray) |> printfn "%A" seems to work fine, with or without new, but List.ofSeq "abcd" |> List.toArray) |> new System.String |> printfn "%A" fails. Why?

  • Miron Brezuleanu
    Miron Brezuleanu about 14 years
    OK, this limitation makes sense performance-wise (creating a lambda that's probably hard to optimize away can probably hurt performance in way that's difficult to detect). Any pointer on why 'new' is optional? To make creating objects by reflection blend in better with the Ocaml/F# syntax? Thanks!
  • Miron Brezuleanu
    Miron Brezuleanu about 14 years
    Kind of hard to pick one of the answers, I'll pick this one because it references another related question. :-)
  • Endrju
    Endrju about 9 years
    "It seems object constructors aren't composable so you can't pass them as a function." This is finally changing. github.com/fsharp/FSharpLangDesign/blob/master/FSharp-4.0/…
  • reggaeguitar
    reggaeguitar almost 8 years
    I get a compiler error when trying the third snippet, it says "Invalid use of a type name and/or object constructor...."
  • gradbot
    gradbot almost 8 years
    @reggaeguitar that error means you are running an older version of F#. You need to update to F# 4.0 which comes with VS 2015.
  • JJS
    JJS over 5 years
    > Constructors are first-class functions as of F# 4.0 is a gem. Thanks!

Related