Подтвердить что ты не робот

F #, char seq → строки

Быстрый вопрос, который может быть более напыщенным (но я надеюсь, что я просвещен).

В F # строка совместима с Seq так, что "abcd" | > Seq.map f будет работать с строкой.

Это блестящее средство для работы со строками, например, чтобы взять первые 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".

Есть ли причина, по которой мои ожидания от строковой манипуляции высокого уровня ошибочны в этом случае?

Есть ли у кого-нибудь рекомендация по подходящему подходу к этому, я чувствую, что мне что-то не хватает.

4b9b3361

Ответ 1

Я просто изучал это сам. Я обнаружил, что System.String.Concat работает очень хорошо, например.

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

предположив, что вы открыли System.

Ответ 2

Функции модуля Seq имеют дело только с последовательностями - то есть, когда вы вызываете их с помощью string, они только "видят" a 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

Ответ 3

F # имеет String module, который содержит некоторые функции модуля Seq, специализированные для строк.