A quick question that may be more of a rant (but I hope to be enlightened instead).
In F# a string is compatible with Seq such that "abcd" |> Seq.map f will work on a string.
This is a brilliant facility for working with strings, for example to take the first 5 chars from a string:
"abcdef01234567" |> Seq.take 5
Or removing duplicate characters:
"abcdeeeeeee" |> Seq.distinct
The problem being that once you have the char seq result, it becomes extremely awkward to convert this back to a string again, String.concat "" requires that the members are strings, so I end up doing this a lot:
"abcdef01234567"
|> Seq.take 5
|> Seq.map string
|> String.concat ""
So much so that I have a function I use in 90% of my projects:
let toString : char seq -> string = Seq.map string >> String.concat ""
I feel this is over the top, but everywhere I look to find an alternative I am met with heinous things like StringBuilder or inlining a lambda and using new:
"abcdef01234567"
|> Seq.take 5
|> Seq.toArray
|> fun cs -> new string (cs) (* note you cannot just |> string *)
My (perhaps crazy) expectation that I would like to see in the language is that when Seq is used on string, the type signature from the resulting expression should be string -> string. Meaning, what goes in is what comes out. "abcd" |> Seq.take 3 = "abc".
Is there a reason my expectations of high level string manipulation is mistaken in this case?
Does anyone have a recommendation for approaching this in a nice manner, I feel like I must be missing something.
System.String("aa" |> Seq.take 1 |> Seq.toArray)
which is slightly better - usingSystem.String
gets an implicitnew
for free – Modest"abcdef01234567".Substring(0, 5)
? I would imagine that the F# String module lacks thetake
function precisely because this instance method exists in the framework. – Hostetter