web-dev-qa-db-ja.com

F#、charseq->文字列

もっと暴言かもしれない簡単な質問(しかし、代わりに悟りを開いてほしい)。

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"。

この場合、高レベルの文字列操作に対する私の期待が誤っている理由はありますか?

誰かがこれにうまくアプローチするための推奨事項を持っていますか、私は何かが欠けているに違いないと感じています。

25
user1158550

私はこれを自分で調べていました。 System.String.Concatが非常にうまく機能することがわかりました。

"abcdef01234567" |> Seq.take 5 |> String.Concat;;

Systemを開いたと仮定します。

24

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
12
Jack P.

F#には String module があり、文字列に特化したSeqモジュール機能の一部が含まれています。

7
Lee

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)
4
Cameron Taggart