From 3ab4995130c84247c5917a11dfc29728bf1e81d3 Mon Sep 17 00:00:00 2001 From: Kento Sugama Date: Thu, 2 Feb 2023 14:44:04 -0800 Subject: [PATCH 1/4] add utility function --- src/Nat.mo | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Nat.mo b/src/Nat.mo index 8b0b9ded..8ff1ab65 100644 --- a/src/Nat.mo +++ b/src/Nat.mo @@ -6,6 +6,7 @@ import Int "Int"; import Order "Order"; import Prim "mo:⛔"; +import Char "Char"; module { @@ -13,7 +14,20 @@ module { public type Nat = Prim.Types.Nat; /// Conversion. - public let toText : Nat -> Text = Int.toText; + public func toText(n : Nat) : Text = Int.toText n; + + public func fromText(text : Text) : ?Nat { + var n = 0; + for (c in text.chars()) { + if (Char.isDigit(c)) { + let charAsNat = Prim.nat32ToNat(Prim.charToNat32(c) -% Prim.charToNat32('0')); + n := n * 10 + charAsNat + } else { + return null + } + }; + ?n + }; /// Returns the minimum of `x` and `y`. public func min(x : Nat, y : Nat) : Nat { From f918e2fc8c4ac40aee23041dfcb92b400394c5ba Mon Sep 17 00:00:00 2001 From: Kento Sugama Date: Thu, 2 Feb 2023 15:26:44 -0800 Subject: [PATCH 2/4] flesh out documentation --- src/Nat.mo | 233 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 223 insertions(+), 10 deletions(-) diff --git a/src/Nat.mo b/src/Nat.mo index 8ff1ab65..d3d1d751 100644 --- a/src/Nat.mo +++ b/src/Nat.mo @@ -1,7 +1,12 @@ -/// Natural numbers +/// Utility functions for working with natural numbers. /// /// Most operations on natural numbers (e.g. addition) are available as built-in operators (e.g. `1 + 1`). /// This module provides equivalent functions and `Text` conversion. +/// +/// Import from the base library to use this module. +/// ```motoko name=import +/// import Nat "mo:base/Nat"; +/// ``` import Int "Int"; import Order "Order"; @@ -13,10 +18,25 @@ module { /// Infinite precision natural numbers. public type Nat = Prim.Types.Nat; - /// Conversion. + /// Converts a natural number to its textual representation. + /// + /// Example: + /// ```motoko include=import + /// Nat.toText 1234 // => "1234" + /// ``` public func toText(n : Nat) : Text = Int.toText n; + /// Creates a natural number from its textual representation. Returns `null` + /// if the input is not a valid natural number. + /// + /// Example: + /// ```motoko include=import + /// Nat.fromText "1234" // => ?1234 + /// ``` public func fromText(text : Text) : ?Nat { + if (text == "") { + return null + }; var n = 0; for (c in text.chars()) { if (Char.isDigit(c)) { @@ -30,57 +50,250 @@ module { }; /// Returns the minimum of `x` and `y`. + /// + /// Example: + /// ```motoko include=import + /// Nat.min(1, 2) // => 1 + /// ``` public func min(x : Nat, y : Nat) : Nat { if (x < y) { x } else { y } }; /// Returns the maximum of `x` and `y`. + /// + /// Example: + /// ```motoko include=import + /// Nat.max(1, 2) // => 2 + /// ``` public func max(x : Nat, y : Nat) : Nat { if (x < y) { y } else { x } }; - /// Returns `x == y`. + /// Equality function for Nat types. + /// This is equivalent to `x == y`. + /// + /// Example: + /// ```motoko include=import + /// ignore Nat.equal(1, 1); // => true + /// 1 == 1 // => true + /// ``` + /// + /// Note: The reason why this function is defined in this library (in addition + /// to the existing `==` operator) is so that you can use it as a function + /// value to pass to a higher order function. It is not possible to use `==` + /// as a function value at the moment. + /// + /// Example: + /// ```motoko include=import + /// import Buffer "mo:base/Buffer"; + /// + /// let buffer1 = Buffer.Buffer(3); + /// let buffer2 = Buffer.Buffer(3); + /// Buffer.equal(buffer1, buffer2, Nat.equal) // => true + /// ``` public func equal(x : Nat, y : Nat) : Bool { x == y }; - /// Returns `x != y`. + /// Inequality function for Nat types. + /// This is equivalent to `x != y`. + /// + /// Example: + /// ```motoko include=import + /// ignore Nat.notEqual(1, 2); // => true + /// 1 != 2 // => true + /// ``` + /// + /// Note: The reason why this function is defined in this library (in addition + /// to the existing `!=` operator) is so that you can use it as a function + /// value to pass to a higher order function. It is not possible to use `!=` + /// as a function value at the moment. public func notEqual(x : Nat, y : Nat) : Bool { x != y }; - /// Returns `x < y`. + /// "Less than" function for Nat types. + /// This is equivalent to `x < y`. + /// + /// Example: + /// ```motoko include=import + /// ignore Nat.less(1, 2); // => true + /// 1 < 2 // => true + /// ``` + /// + /// Note: The reason why this function is defined in this library (in addition + /// to the existing `<` operator) is so that you can use it as a function + /// value to pass to a higher order function. It is not possible to use `<` + /// as a function value at the moment. public func less(x : Nat, y : Nat) : Bool { x < y }; - /// Returns `x <= y`. + /// "Less than or equal" function for Nat types. + /// This is equivalent to `x <= y`. + /// + /// Example: + /// ```motoko include=import + /// ignore Nat.lessOrEqual(1, 2); // => true + /// 1 <= 2 // => true + /// ``` + /// + /// Note: The reason why this function is defined in this library (in addition + /// to the existing `<=` operator) is so that you can use it as a function + /// value to pass to a higher order function. It is not possible to use `<=` + /// as a function value at the moment. public func lessOrEqual(x : Nat, y : Nat) : Bool { x <= y }; - /// Returns `x > y`. + /// "Greater than" function for Nat types. + /// This is equivalent to `x > y`. + /// + /// Example: + /// ```motoko include=import + /// ignore Nat.greater(2, 1); // => true + /// 2 > 1 // => true + /// ``` + /// + /// Note: The reason why this function is defined in this library (in addition + /// to the existing `>` operator) is so that you can use it as a function + /// value to pass to a higher order function. It is not possible to use `>` + /// as a function value at the moment. public func greater(x : Nat, y : Nat) : Bool { x > y }; - /// Returns `x >= y`. + /// "Greater than or equal" function for Nat types. + /// This is equivalent to `x >= y`. + /// + /// Example: + /// ```motoko include=import + /// ignore Nat.greaterOrEqual(2, 1); // => true + /// 2 >= 1 // => true + /// ``` + /// + /// Note: The reason why this function is defined in this library (in addition + /// to the existing `>=` operator) is so that you can use it as a function + /// value to pass to a higher order function. It is not possible to use `>=` + /// as a function value at the moment. public func greaterOrEqual(x : Nat, y : Nat) : Bool { x >= y }; - /// Returns the order of `x` and `y`. + /// General purpose comparison function for `Nat`. Returns the `Order` ( + /// either `#less`, `#equal`, or `#greater`) of comparing `x` with `y`. + /// + /// Example: + /// ```motoko include=import + /// Nat.compare(2, 3) // => #less + /// ``` + /// + /// Note: The reason why this function is defined in this library (in addition + /// to the existing `>=` operator) is so that you can use it as a function + /// value to pass to a higher order function. It is not possible to use `>=` + /// as a function value at the moment. + /// + /// Example: + /// ```motoko include=import + /// import Array "mo:base/Array"; + /// Array.sort([2, 3, 1], Nat.compare) // => [1, 2, 3] + /// ``` public func compare(x : Nat, y : Nat) : { #less; #equal; #greater } { if (x < y) { #less } else if (x == y) { #equal } else { #greater } }; /// Returns the sum of `x` and `y`, `x + y`. + /// + /// Example: + /// ```motoko include=import + /// ignore Nat.add(1, 2); // => 3 + /// 1 + 2 // => 3 + /// ``` + /// + /// Note: The reason why this function is defined in this library (in addition + /// to the existing `+` operator) is so that you can use it as a function + /// value to pass to a higher order function. It is not possible to use `+` + /// as a function value at the moment. + /// + /// Example: + /// ```motoko include=import + /// import Array "mo:base/Array"; + /// Array.foldLeft([2, 3, 1], 0, Nat.add) // => 6 + /// ``` public func add(x : Nat, y : Nat) : Nat { x + y }; /// Returns the difference of `x` and `y`, `x - y`. - /// Traps on underflow. + /// Traps on underflow below `0`. + /// + /// Example: + /// ```motoko include=import + /// ignore Nat.sub(2, 1); // => 1 + /// // Add a type annotation to avoid a warning about the subtraction + /// 2 - 1 : Nat // => 1 + /// ``` + /// + /// Note: The reason why this function is defined in this library (in addition + /// to the existing `-` operator) is so that you can use it as a function + /// value to pass to a higher order function. It is not possible to use `-` + /// as a function value at the moment. + /// + /// Example: + /// ```motoko include=import + /// import Array "mo:base/Array"; + /// Array.foldLeft([2, 3, 1], 10, Nat.sub) // => 4 + /// ``` public func sub(x : Nat, y : Nat) : Nat { x - y }; /// Returns the product of `x` and `y`, `x * y`. + /// + /// Example: + /// ```motoko include=import + /// ignore Nat.mul(2, 3); // => 6 + /// 2 * 3 // => 6 + /// ``` + /// + /// Note: The reason why this function is defined in this library (in addition + /// to the existing `*` operator) is so that you can use it as a function + /// value to pass to a higher order function. It is not possible to use `*` + /// as a function value at the moment. + /// + /// Example: + /// ```motoko include=import + /// import Array "mo:base/Array"; + /// Array.foldLeft([2, 3, 1], 1, Nat.mul) // => 6 + /// ``` public func mul(x : Nat, y : Nat) : Nat { x * y }; /// Returns the division of `x` by `y`, `x / y`. /// Traps when `y` is zero. + /// + /// Example: + /// ```motoko include=import + /// ignore Nat.div(6, 2); // => 3 + /// 6 / 2 // => 3 + /// ``` + /// + /// Note: The reason why this function is defined in this library (in addition + /// to the existing `/` operator) is so that you can use it as a function + /// value to pass to a higher order function. It is not possible to use `/` + /// as a function value at the moment. public func div(x : Nat, y : Nat) : Nat { x / y }; /// Returns the remainder of `x` divided by `y`, `x % y`. /// Traps when `y` is zero. + /// + /// Example: + /// ```motoko include=import + /// ignore Nat.rem(6, 4); // => 2 + /// 6 % 4 // => 2 + /// ``` + /// + /// Note: The reason why this function is defined in this library (in addition + /// to the existing `%` operator) is so that you can use it as a function + /// value to pass to a higher order function. It is not possible to use `%` + /// as a function value at the moment. public func rem(x : Nat, y : Nat) : Nat { x % y }; /// Returns `x` to the power of `y`, `x ** y`. + /// + /// Example: + /// ```motoko include=import + /// ignore Nat.pow(2, 3); // => 8 + /// 2 ** 3 // => 8 + /// ``` + /// + /// Note: The reason why this function is defined in this library (in addition + /// to the existing `**` operator) is so that you can use it as a function + /// value to pass to a higher order function. It is not possible to use `**` + /// as a function value at the moment. public func pow(x : Nat, y : Nat) : Nat { x ** y }; } From 107f03103edd1320233f0676d72f85baab773562 Mon Sep 17 00:00:00 2001 From: Kento Sugama Date: Fri, 3 Feb 2023 15:52:54 -0800 Subject: [PATCH 3/4] Incorporate feedback --- src/Nat.mo | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/Nat.mo b/src/Nat.mo index d3d1d751..9281814b 100644 --- a/src/Nat.mo +++ b/src/Nat.mo @@ -1,4 +1,4 @@ -/// Utility functions for working with natural numbers. +/// Natural numbers with infinite precision. /// /// Most operations on natural numbers (e.g. addition) are available as built-in operators (e.g. `1 + 1`). /// This module provides equivalent functions and `Text` conversion. @@ -18,7 +18,8 @@ module { /// Infinite precision natural numbers. public type Nat = Prim.Types.Nat; - /// Converts a natural number to its textual representation. + /// Converts a natural number to its textual representation. Textual + /// representation _do not_ contain underscores to represent commas. /// /// Example: /// ```motoko include=import @@ -29,6 +30,8 @@ module { /// Creates a natural number from its textual representation. Returns `null` /// if the input is not a valid natural number. /// + /// Note: The textual representation _must not_ contain underscores. + /// /// Example: /// ```motoko include=import /// Nat.fromText "1234" // => ?1234 @@ -190,7 +193,8 @@ module { if (x < y) { #less } else if (x == y) { #equal } else { #greater } }; - /// Returns the sum of `x` and `y`, `x + y`. + /// Returns the sum of `x` and `y`, `x + y`. This operator will never overflow + /// because `Nat` is infinite precision. /// /// Example: /// ```motoko include=import @@ -232,7 +236,8 @@ module { /// ``` public func sub(x : Nat, y : Nat) : Nat { x - y }; - /// Returns the product of `x` and `y`, `x * y`. + /// Returns the product of `x` and `y`, `x * y`. This operator will never + /// overflow because `Nat` is infinite precision. /// /// Example: /// ```motoko include=import @@ -252,9 +257,12 @@ module { /// ``` public func mul(x : Nat, y : Nat) : Nat { x * y }; - /// Returns the division of `x` by `y`, `x / y`. + /// Returns the unsigned integer division of `x` by `y`, `x / y`. /// Traps when `y` is zero. /// + /// The quotient is rounded down, which is equivalent to truncating the + /// decimal places of the quotient. + /// /// Example: /// ```motoko include=import /// ignore Nat.div(6, 2); // => 3 @@ -267,7 +275,7 @@ module { /// as a function value at the moment. public func div(x : Nat, y : Nat) : Nat { x / y }; - /// Returns the remainder of `x` divided by `y`, `x % y`. + /// Returns the remainder of unsigned integer division of `x` by `y`, `x % y`. /// Traps when `y` is zero. /// /// Example: @@ -282,7 +290,8 @@ module { /// as a function value at the moment. public func rem(x : Nat, y : Nat) : Nat { x % y }; - /// Returns `x` to the power of `y`, `x ** y`. + /// Returns `x` to the power of `y`, `x ** y`. Traps when `y > 32`. This operator + /// will never overflow because `Nat` is infinite precision. /// /// Example: /// ```motoko include=import From 69d940a09978888d717bc7fa60019eff154e793d Mon Sep 17 00:00:00 2001 From: Kento Sugama <107421898+kentosugama@users.noreply.github.com> Date: Mon, 6 Feb 2023 12:33:13 -0500 Subject: [PATCH 4/4] Typo in `pow` doc --- src/Nat.mo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nat.mo b/src/Nat.mo index 9281814b..6fd9fcf1 100644 --- a/src/Nat.mo +++ b/src/Nat.mo @@ -290,7 +290,7 @@ module { /// as a function value at the moment. public func rem(x : Nat, y : Nat) : Nat { x % y }; - /// Returns `x` to the power of `y`, `x ** y`. Traps when `y > 32`. This operator + /// Returns `x` to the power of `y`, `x ** y`. Traps when `y > 2^32`. This operator /// will never overflow because `Nat` is infinite precision. /// /// Example: