もっと暴言かもしれない簡単な質問(しかし、代わりに悟りを開いてほしい)。
F#では、文字列はSeqと互換性があるため、 "abcd" |> Seq.mapfは文字列で機能します。
これは、文字列を操作するための優れた機能です。たとえば、文字列から最初の5文字を取得します。
"abcdef01234567" |> Seq.take 5
または重複する文字を削除する:
"abcdeeeeeee" |> Seq.distinct
問題は、char seqの結果が得られたら、これを再び文字列に変換するのが非常に厄介になることです。String.concat ""では、メンバーが文字列である必要があるため、これを頻繁に行うことになります。
"abcdef01234567"
|> Seq.take 5
|> Seq.map string
|> String.concat ""
プロジェクトの90%で使用している機能があるほどです。
let toString : char seq -> string = Seq.map string >> String.concat ""
これはやり過ぎだと思いますが、StringBuilderやラムダのインライン化、新しいものの使用などの凶悪なものに遭遇する代替案を探すところはどこでもです。
"abcdef01234567"
|> Seq.take 5
|> Seq.toArray
|> fun cs -> new string (cs) (* note you cannot just |> string *)
私がこの言語で見たいと思う(おそらくクレイジーな)期待は、Seqが文字列で使用される場合、結果の式からの型シグネチャは文字列->文字列でなければならないということです。つまり、入ってくるのは出てくるものです。 "abcd" |> Seq.take 3 = "abc"。
この場合、高レベルの文字列操作に対する私の期待が誤っている理由はありますか?
誰かがこれにうまくアプローチするための推奨事項を持っていますか、私は何かが欠けているに違いないと感じています。
私はこれを自分で調べていました。 System.String.Concatが非常にうまく機能することがわかりました。
"abcdef01234567" |> Seq.take 5 |> String.Concat;;
System
を開いたと仮定します。
Seq
モジュールの関数は、シーケンスのみを処理します。つまり、string
を使用して呼び出すと、Seq<char>
のみを「認識」し、それに応じて操作します。引数がstring
であるかどうかを確認するために特別なチェックを行い、特別なアクション(たとえば、文字列専用の関数の最適化バージョン)を実行した場合でも、それをSeq<char>
として返す必要があります。 F#型システムをなだめるには、この場合、どこでも戻り値をチェックして、それが実際にstring
であるかどうかを確認する必要があります。
幸いなことに、F#には、作成しているコードの一部にショートカットが組み込まれています。例えば:
"abcdef01234567" |> Seq.take 5
次のように短縮できます。
"abcdef01234567".[..4] // Returns the first _5_ characters (indices 0-4).
ただし、他のいくつかはSeq
を使用するか、文字列を操作するために独自の最適化された実装を作成する必要があります。
文字列内の個別の文字を取得する関数は次のとおりです。
open System.Collections.Generic
let distinctChars str =
let chars = HashSet ()
let len = String.length str
for i = 0 to len - 1 do
chars.Add str.[i] |> ignore
chars
F#には String module があり、文字列に特化したSeq
モジュール機能の一部が含まれています。
F#は、この質問が5年前に行われて以来、コンストラクターを関数として使用できるようになりました。 String(Char []) を使用して文字を文字列に変換します。 F#シーケンスまたはF#リストとの間で変換できますが、おそらく String.ToCharArray メソッドを使用してF#配列モジュールを使用するだけです。
printfn "%s" ("abcdef01234567".ToCharArray() |> Array.take 5 |> String)
本当にchar seq
を使用したい場合は、次のように文字列にパイプできます。
printfn "%s" ("abcdef01234567" |> Seq.take 5 |> Array.ofSeq |> String)