Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sorted the string.fsi entries and added examples to each one #12130

Merged
merged 8 commits into from
Sep 9, 2021
232 changes: 172 additions & 60 deletions src/fsharp/FSharp.Core/string.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,29 @@ namespace Microsoft.FSharp.Core
[<RequireQualifiedAccess>]
module String =

/// <summary>Builds a new string whose characters are the results of applying the function <c>mapping</c>
/// to each of the characters of the input string and concatenating the resulting
/// strings.</summary>
///
/// <param name="mapping">The function to produce a string from each character of the input string.</param>
/// <param name="str">The input string.</param>
///
/// <returns>The concatenated string.</returns>
///
/// <example> The following samples shows how to interspace spaces in a text
Copy link
Member

@baronfel baronfel Sep 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually the first time I've seen multiple examples in the wild, so congratulations on surprising me :)

I did check, and FSharp.Formatting and FsAutoComplete do handle multiple examples just fine, so this shouldn't be a problem from the perspective of tooling consuming these docs.

@dsyme it does make me want some kind of 'example identifier' for use in generation, for example generating a link of FSharp.Core.StringModule#collect-example-collect-space in order to jump to the specific example, but that's just some off-the-cuff musing. (FSharp.Formatting already generates a numeric identifier for this case, but something more stable might be useful?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dsyme it does make me want some kind of 'example identifier' for use in generation, for example generating a link of FSharp.Core.StringModule#collect-example-collect-space in order to jump to the specific example, but that's just some off-the-cuff musing. (FSharp.Formatting already generates a numeric identifier for this case, but something more stable might be useful?)

Makes sense, yes, even just collect-example-1

Copy link
Contributor

@dsyme dsyme Sep 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just use <example id="collect-whatever"> I think

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did check, and FSharp.Formatting and FsAutoComplete do handle multiple examples just fine, so this shouldn't be a problem from the perspective of tooling consuming these docs.

Thank you for checking this!!!!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, that's what I was getting at, I just wonder if it's worth codifying that in the tooling RFC and adding support to FSharp.Formatting then.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, that's what I was getting at, I just wonder if it's worth codifying that in the tooling RFC and adding support to FSharp.Formatting then.

Absolutely

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tracking this on the RFC and in FSharp.Formatting

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added ids to every example tag

Copy link
Contributor Author

@MecuStefan MecuStefan Sep 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Facepalm, I get it now: you want to generate the ids ... . I should remove them then?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, I'd keep them. My intent was for the author to give them meaningful ids. There is some last-chance id generation happening in FSharp.Formatting, but the MR I have up now always takes the id that is present if there is one. So, all in all, I think what you have now is great 👍

/// <code lang="fsharp">
/// String.collect (sprintf "%c ") "Stefan says: Hi!" // evaluates "S t e f a n s a y s : H i ! "
MecuStefan marked this conversation as resolved.
Show resolved Hide resolved
/// </code>
/// </example>
///
/// <example>How to show the ASCII representation of a very secret text:
/// <code lang="fsharp">
/// String.collect (fun chr -> int chr |> sprintf "%d ") "Secret" // evaluates "83 101 99 114 101 116 "
/// </code>
/// </example>
[<CompiledName("Collect")>]
val collect: mapping:(char -> string) -> str:string -> string

/// <summary>Returns a new string made by concatenating the given strings
/// with separator <c>sep</c>, that is <c>a1 + sep + ... + sep + aN</c>.</summary>
/// <param name="sep">The separator string to be inserted between the strings
Expand All @@ -27,54 +50,32 @@ namespace Microsoft.FSharp.Core
/// <returns>A new string consisting of the concatenated strings separated by
/// the separation string.</returns>
/// <exception cref="T:System.ArgumentNullException">Thrown when <c>strings</c> is null.</exception>
///
/// <example>
/// <code lang="fsharp">
/// String.concat " " ["Stefan"; "says:"; "Hello"; "there!"] // evaluates "Stefan says: Hello there!"
/// [0..9] |> List.map string |> String.concat "" // evaluates "0123456789"
/// String.concat "!" ["No exclamation point here"] // evaluates "No exclamation point here"
/// </code>
MecuStefan marked this conversation as resolved.
Show resolved Hide resolved
/// </example>
[<CompiledName("Concat")>]
val concat: sep:string -> strings: seq<string> -> string

/// <summary>Applies the function <c>action</c> to each character in the string.</summary>
///
/// <param name="action">The function to be applied to each character of the string.</param>
/// <param name="str">The input string.</param>
[<CompiledName("Iterate")>]
val iter: action:(char -> unit) -> str:string -> unit

/// <summary>Applies the function <c>action</c> to the index of each character in the string and the
/// character itself.</summary>
///
/// <param name="action">The function to apply to each character and index of the string.</param>
/// <param name="str">The input string.</param>
[<CompiledName("IterateIndexed")>]
val iteri: action:(int -> char -> unit) -> str:string -> unit

/// <summary>Builds a new string whose characters are the results of applying the function <c>mapping</c>
/// to each of the characters of the input string.</summary>
///
/// <param name="mapping">The function to apply to the characters of the string.</param>
/// <param name="str">The input string.</param>
///
/// <returns>The resulting string.</returns>
[<CompiledName("Map")>]
val map: mapping:(char -> char) -> str:string -> string

/// <summary>Builds a new string whose characters are the results of applying the function <c>mapping</c>
/// to each character and index of the input string.</summary>
///
/// <param name="mapping">The function to apply to each character and index of the string.</param>
/// <param name="str">The input string.</param>
///
/// <returns>The resulting string.</returns>
[<CompiledName("MapIndexed")>]
val mapi: mapping:(int -> char -> char) -> str:string -> string

/// <summary>Builds a new string whose characters are the results of applying the function <c>mapping</c>
/// to each of the characters of the input string and concatenating the resulting
/// strings.</summary>
/// <summary>Tests if any character of the string satisfies the given predicate.</summary>
///
/// <param name="mapping">The function to produce a string from each character of the input string.</param>
/// <param name="predicate">The function to test each character of the string.</param>
/// <param name="str">The input string.</param>
///
/// <returns>The concatenated string.</returns>
[<CompiledName("Collect")>]
val collect: mapping:(char -> string) -> str:string -> string
/// <returns>True if any character returns true for the predicate and false otherwise.</returns>
///
/// <example> Looking for uppercase characters
/// <code lang="fsharp">
/// String.exists System.Char.IsUpper "Yoda" // evaluates true
/// String.exists System.Char.IsUpper "nope" // evaluates false
/// </code>
MecuStefan marked this conversation as resolved.
Show resolved Hide resolved
/// </example>
[<CompiledName("Exists")>]
val exists: predicate:(char -> bool) -> str:string -> bool

/// <summary>Builds a new string containing only the characters of the input string
/// for which the given predicate returns "true".</summary>
Expand All @@ -85,9 +86,32 @@ namespace Microsoft.FSharp.Core
/// <param name="str">The input string.</param>
///
/// <returns>The resulting string.</returns>
///
/// <example> Filtering out just alphanumeric characters or just digits
/// <code lang="fsharp">
/// String.filter System.Uri.IsHexDigit "0 1 2 3 4 5 6 7 8 9 a A m M" // evaluates "123456789aA"
/// String.filter System.Char.IsDigit "hello" // evaluates ""
/// </code>
MecuStefan marked this conversation as resolved.
Show resolved Hide resolved
/// </example>
[<CompiledName("Filter")>]
val filter: predicate:(char -> bool) -> str:string -> string

/// <summary>Tests if all characters in the string satisfy the given predicate.</summary>
///
/// <param name="predicate">The function to test each character of the string.</param>
/// <param name="str">The input string.</param>
///
/// <returns>True if all characters return true for the predicate and false otherwise.</returns>
///
/// <example> Looking for lowercase characters
/// <code lang="fsharp">
/// String.forall System.Char.IsLower "all are lower" // evaluates false
/// String.forall System.Char.IsLower "allarelower" // evaluates true
/// </code>
/// </example>
[<CompiledName("ForAll")>]
val forall: predicate:(char -> bool) -> str:string -> bool

/// <summary>Builds a new string whose characters are the results of applying the function <c>mapping</c>
/// to each index from <c>0</c> to <c>count-1</c> and concatenating the resulting
/// strings.</summary>
Expand All @@ -98,26 +122,115 @@ namespace Microsoft.FSharp.Core
///
/// <returns>The constructed string.</returns>
/// <exception cref="T:System.ArgumentException">Thrown when <c>count</c> is negative.</exception>
///
/// <example> Enumerate digits ASCII codes
/// <code lang="fsharp">
/// String.init 10 (fun i -> int '0' + i |> sprintf "%d ") // evaluates "48 49 50 51 52 53 54 55 56 57 "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These lines are getting too long I think (102 characters), suggest a maximum of 80 with a preference for 60

        /// <code lang="fsharp">
        /// String.init 10 (fun i -> int '0' + i |> sprintf "%d ")
        /// </code>
        /// evaluates to
        /// <code>
        /// "48 49 50 51 52 53 54 55 56 57 "
        /// </code>

across all the samples.

/// </code>
/// </example>
[<CompiledName("Initialize")>]
val init: count:int -> initializer:(int -> string) -> string

/// <summary>Tests if all characters in the string satisfy the given predicate.</summary>
/// <summary>Applies the function <c>action</c> to each character in the string.</summary>
///
/// <param name="predicate">The function to test each character of the string.</param>
/// <param name="action">The function to be applied to each character of the string.</param>
/// <param name="str">The input string.</param>
///
/// <example>
/// <code lang="fsharp">
/// String.iter (fun c -> printfn "%c %d" c (int c)) "Hello"
/// // evaluates unit
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

English language parts outside of <code>

/// // prints:
/// H 72
/// e 101
/// l 108
/// l 108
/// o 111
/// </code>
/// </example>
[<CompiledName("Iterate")>]
val iter: action:(char -> unit) -> str:string -> unit

/// <summary>Applies the function <c>action</c> to the index of each character in the string and the
/// character itself.</summary>
///
/// <returns>True if all characters return true for the predicate and false otherwise.</returns>
[<CompiledName("ForAll")>]
val forall: predicate:(char -> bool) -> str:string -> bool
/// <param name="action">The function to apply to each character and index of the string.</param>
/// <param name="str">The input string.</param>
///
/// <example>
/// <code lang="fsharp">
/// String.length null // evaluates 0
/// String.length "" // evaluates 0
/// String.length "123" // evaluates 3
/// </code>
/// </example>
///
/// <example>
MecuStefan marked this conversation as resolved.
Show resolved Hide resolved
/// <code lang="fsharp">
/// String.iteri (fun i c -> printfn "%d. %c %d" (i + 1) c (int c)) "Hello"
/// // evaluates unit
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these english language parts should not be in <code>

/// // prints:
/// 1. H 72
/// 2. e 101
/// 3. l 108
/// 4. l 108
/// 5. o 111
/// </code>
/// </example>
[<CompiledName("IterateIndexed")>]
val iteri: action:(int -> char -> unit) -> str:string -> unit

/// <summary>Tests if any character of the string satisfies the given predicate.</summary>
/// <summary>Returns the length of the string.</summary>
///
/// <param name="predicate">The function to test each character of the string.</param>
/// <param name="str">The input string.</param>
///
/// <returns>True if any character returns true for the predicate and false otherwise.</returns>
[<CompiledName("Exists")>]
val exists: predicate:(char -> bool) -> str:string -> bool
/// <returns>The number of characters in the string.</returns>
///
/// <example>
/// <code lang="fsharp">
/// String.length null // evaluates 0
/// String.length "" // evaluates 0
/// String.length "123" // evaluates 3
/// </code>
/// </example>
[<CompiledName("Length")>]
val length: str:string -> int

/// <summary>Builds a new string whose characters are the results of applying the function <c>mapping</c>
/// to each of the characters of the input string.</summary>
///
/// <param name="mapping">The function to apply to the characters of the string.</param>
/// <param name="str">The input string.</param>
///
/// <returns>The resulting string.</returns>
///
/// <example> Changing case to upper for all characters in the input string
/// <code lang="fsharp">
/// String.map System.Char.ToUpper "Hello there!" // evaluates "HELLO THERE!"
/// </code>
/// </example>
[<CompiledName("Map")>]
val map: mapping:(char -> char) -> str:string -> string

/// <summary>Builds a new string whose characters are the results of applying the function <c>mapping</c>
/// to each character and index of the input string.</summary>
///
/// <param name="mapping">The function to apply to each character and index of the string.</param>
/// <param name="str">The input string.</param>
///
/// <returns>The resulting string.</returns>
///
/// <example> Alternating case for all characters in the input string
/// <code lang="fsharp">
/// let alternateCase indx chr =
/// if 0 = indx % 2
/// then System.Char.ToUpper chr
/// else System.Char.ToLower chr
/// String.mapi alternateCase "Hello there!" // evaluates "HeLlO ThErE!"
/// </code>
/// </example>
[<CompiledName("MapIndexed")>]
val mapi: mapping:(int -> char -> char) -> str:string -> string

/// <summary>Returns a string by concatenating <c>count</c> instances of <c>str</c>.</summary>
///
Expand All @@ -126,14 +239,13 @@ namespace Microsoft.FSharp.Core
///
/// <returns>The concatenated string.</returns>
/// <exception cref="T:System.ArgumentException">Thrown when <c>count</c> is negative.</exception>
///
/// <example>
/// <code lang="fsharp">
/// String.replicate 3 "Do it! " // evaluates "Do it! Do it! Do it! "
/// </code>
/// </example>
[<CompiledName("Replicate")>]
val replicate: count:int -> str: string -> string

/// <summary>Returns the length of the string.</summary>
///
/// <param name="str">The input string.</param>
///
/// <returns>The number of characters in the string.</returns>
[<CompiledName("Length")>]
val length: str:string -> int