29

暴言のような簡単な質問です (しかし、代わりに啓発されることを願っています)。

F# では、"abcd" |> Seq.map f が文字列に対して機能するように、文字列は Seq と互換性があります。

これは、たとえば文字列から最初の 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 やラムダのインライン化、new の使用などの凶悪なことに遭遇します。

"abcdef01234567" 
|> Seq.take 5
|> Seq.toArray 
|> fun cs -> new string (cs) (* note you cannot just |> string *)

私が言語で見たいと思っている私の (おそらくクレイジーな) 期待は、Seq が文字列で使用される場合、結果の式の型シグネチャは文字列 -> 文字列になるはずです。つまり、入ったものが出てくるということです。"abcd" |> Seq.take 3 = "abc".

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

これに良い方法でアプローチするための推奨事項はありますか?何かが欠けているように感じます。

4

4 に答える 4

28

私はちょうどこれを自分で研究していました。System.String.Concat はかなりうまく機能することがわかりました。

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

を開いていると仮定しますSystem

于 2014-05-09T19:22:47.090 に答える
12

モジュール内の関数はSeqシーケンスのみを処理します。つまり、 a で関数を呼び出すと、 astringのみを「見て」、Seq<char>それに応じて操作します。引数が であるかどうかを確認するために特別なチェックを行い、何らかの特別なアクション (たとえば、文字列のためだけに最適化されたバージョンの関数) を行ったとしても、F# 型システムに適合させるために、stringそれを として返す必要があります。Seq<char>- その場合、戻り値をどこでもチェックして、実際に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
于 2013-02-03T00:13:14.220 に答える
7

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

于 2013-02-03T00:37:22.470 に答える