From 21986383a1b7a79699d6e52e82fe4e80cc14ff4e Mon Sep 17 00:00:00 2001 From: Jakub Hampl Date: Tue, 5 Sep 2023 12:30:39 +0300 Subject: [PATCH 1/4] Initial draft of Float.Extra --- docs.json | 2 +- elm.json | 1 + review/src/ReviewConfig.elm | 2 +- src/Float/Extra.elm | 368 +++++++++++++++++++++++++++++++++ tests/FloatTests.elm | 279 +++++++++++++++++++++++++ tests/elm-verify-examples.json | 1 + 6 files changed, 651 insertions(+), 2 deletions(-) create mode 100644 src/Float/Extra.elm create mode 100644 tests/FloatTests.elm diff --git a/docs.json b/docs.json index 2ad8ebe..66948f3 100644 --- a/docs.json +++ b/docs.json @@ -1 +1 @@ -[{"name":"Array.Extra","comment":" Convenience functions for working with `Array`\n\n\n# observe\n\n@docs all, any, member\n\n\n# alter\n\n@docs reverse, intersperse\n@docs update, pop, removeAt, insertAt\n\n\n## filter\n\n@docs removeWhen, filterMap\n\n\n## part\n\n@docs sliceFrom, sliceUntil, splitAt, unzip\n\n\n## combine\n\n@docs interweave, apply, map2, map3, map4, map5, zip, zip3\n\n\n## resize\n\n@docs resizelRepeat, resizerRepeat, resizelIndexed, resizerIndexed\n\n\n# transform\n\n@docs mapToList, indexedMapToList\n\n","unions":[],"aliases":[],"values":[{"name":"all","comment":" Whether all elements satisfy a given test.\n\n import Array exposing (fromList, empty)\n\n fromList [ 2, 4 ] |> all (\\x -> x < 5)\n --> True\n\n fromList [ 4, 16 ] |> all (\\x -> x < 5)\n --> False\n\n empty |> all (\\x -> x < 5)\n --> True\n\n","type":"(element -> Basics.Bool) -> Array.Array element -> Basics.Bool"},{"name":"any","comment":" Whether at least some elements satisfy a given test.\n\n import Array exposing (fromList, empty)\n\n fromList [ 6, 3 ] |> any (\\x -> x < 5)\n --> True\n\n fromList [ 12, 33 ] |> any (\\x -> x < 5)\n --> False\n\n empty |> any (\\x -> x < 5)\n --> False\n\n","type":"(element -> Basics.Bool) -> Array.Array element -> Basics.Bool"},{"name":"apply","comment":" Apply a given `Array` of changes to all elements.\nIf one `Array` is longer, its extra elements are not used.\n\n import Array exposing (fromList, repeat)\n\n repeat 5 100\n |> apply\n (fromList\n [ \\x -> -x, identity, (+) 10 ]\n )\n --> fromList [ -100, 100, 110 ]\n\n","type":"Array.Array (a -> b) -> Array.Array a -> Array.Array b"},{"name":"filterMap","comment":" Try transforming all elements but only keep the successes.\n\n import Array exposing (fromList)\n\n fromList [ \"3\", \"4.0\", \"5\", \"hats\" ]\n |> filterMap String.toInt\n --> fromList [ 3, 5 ]\n\n","type":"(a -> Maybe.Maybe b) -> Array.Array a -> Array.Array b"},{"name":"indexedMapToList","comment":" Transform all elements with their indexes as the first argument\nand collect the result in a `List`.\n\n import Array exposing (Array, fromList)\n import Html exposing (Html)\n\n type alias Exercise =\n { name : String }\n\n exerciseRender : Int -> Exercise -> Html msg\n exerciseRender index =\n \\exercise ->\n String.concat\n [ \"Exercise #\"\n , String.fromInt (index + 1)\n , \" - \"\n , exercise.name\n ]\n |> Html.text\n\n exercisesRender : Array Exercise -> Html msg\n exercisesRender =\n indexedMapToList renderExercise\n >> Html.div []\n\n","type":"(Basics.Int -> element -> mappedElement) -> Array.Array element -> List.List mappedElement"},{"name":"insertAt","comment":" Insert an element at a given index.\nIf the index is out of bounds, nothing is changed.\n\n import Array exposing (fromList)\n\n fromList [ 'a', 'c' ] |> insertAt 1 'b'\n --> fromList [ 'a', 'b', 'c' ]\n\n fromList [ 'a', 'c' ] |> insertAt -1 'b'\n --> fromList [ 'a', 'c' ]\n\n fromList [ 'a', 'c' ] |> insertAt 100 'b'\n --> fromList [ 'a', 'c' ]\n\n","type":"Basics.Int -> element -> Array.Array element -> Array.Array element"},{"name":"intersperse","comment":" Place a value between all elements.\n\n import Array exposing (fromList)\n\n fromList [ \"turtles\", \"turtles\", \"turtles\" ]\n |> intersperse \"on\"\n --> fromList\n --> [ \"turtles\", \"on\", \"turtles\", \"on\", \"turtles\" ]\n\nTo interlace an `Array`, [`interweave`](#interweave).\n\n","type":"a -> Array.Array a -> Array.Array a"},{"name":"interweave","comment":" Place all elements of a given `Array` between all current elements.\nExtra elements of either `Array` are glued to the end without anything in between.\n\n import Array exposing (fromList, repeat)\n\n fromList [ \"turtles\", \"turtles\", \"turtles\" ]\n |> interweave (repeat 2 \"on\")\n --> fromList [ \"turtles\", \"on\", \"turtles\", \"on\", \"turtles\" ]\n\n fromList [ \"turtles\", \"turtles\", \"turtles\" ]\n |> interweave (repeat 5 \"on\")\n --> fromList [ \"turtles\", \"on\", \"turtles\", \"on\", \"turtles\", \"on\", \"on\", \"on\" ]\n\n fromList [ \"turtles\", \"turtles\", \"turtles\" ]\n |> interweave (repeat 1 \"on\")\n --> fromList [ \"turtles\", \"on\", \"turtles\", \"turtles\" ]\n\n","type":"Array.Array element -> Array.Array element -> Array.Array element"},{"name":"map2","comment":" Combine the elements of two `Array`s with a given function.\nIf one `Array` is longer, its extra elements are not used.\n\n import Array exposing (fromList)\n\n map2 (\\a b -> a + b)\n (fromList [ 1, 2, 3 ])\n (fromList [ 1, 2, 3, 4 ])\n --> fromList [ 2, 4, 6 ]\n\n map2 Tuple.pair\n (fromList [ 1, 2, 3 ])\n (fromList [ 'a', 'b' ])\n --> fromList [ ( 1, 'a' ), ( 2, 'b' ) ]\n\nNote: [`zip`](Array-Extra#zip) can be used instead of `map2 Tuple.pair`.\n\n","type":"(a -> b -> combined) -> Array.Array a -> Array.Array b -> Array.Array combined"},{"name":"map3","comment":" Combine the elements of three `Array`s with the given function. See [`map2`](Array-Extra#map2).\n\nNote: [`zip3`](Array-Extra#zip3) can be used instead of `map3 (\\a b c -> ( a, b, c ))`.\n\n","type":"(a -> b -> c -> combined) -> Array.Array a -> Array.Array b -> Array.Array c -> Array.Array combined"},{"name":"map4","comment":" Combine the elements of four `Array`s with the given function. See [`map2`](Array-Extra#map2).\n","type":"(a -> b -> c -> d -> combined) -> Array.Array a -> Array.Array b -> Array.Array c -> Array.Array d -> Array.Array combined"},{"name":"map5","comment":" Combine the elements of five `Array`s with the given function. See [`map2`](Array-Extra#map2).\n","type":"(a -> b -> c -> d -> e -> combined) -> Array.Array a -> Array.Array b -> Array.Array c -> Array.Array d -> Array.Array e -> Array.Array combined"},{"name":"mapToList","comment":" Apply a function to the elements in the array and collect the result in a List.\n\n import Array exposing (fromList)\n import Html\n\n fromList [ \"a\", \"b\", \"c\" ]\n |> mapToList Html.text\n --> [ Html.text \"a\", Html.text \"b\", Html.text \"c\" ]\n\n","type":"(a -> b) -> Array.Array a -> List.List b"},{"name":"member","comment":" Whether a given value is contained.\n\n import Array exposing (fromList)\n\n fromList [ \"Leonardo\", \"Michelangelo\", \"Donatello\", \"Raphael\" ]\n |> member \"Donatello\"\n --> True\n\n fromList [ \"Leonardo\", \"Michelangelo\" ]\n |> member \"Raphael\"\n --> False\n\nFor checking if some aspect is present, use [`any`](#any).\n\n","type":"element -> Array.Array element -> Basics.Bool"},{"name":"pop","comment":" Remove the last element.\n\n import Array exposing (fromList, empty)\n\n fromList [ 1, 2, 3 ] |> pop\n --> fromList [ 1, 2 ]\n\n empty |> pop\n --> empty\n\n","type":"Array.Array a -> Array.Array a"},{"name":"removeAt","comment":" Remove the element at a given index.\nIf the index is out of bounds, nothing is changed.\n\n import Array exposing (fromList)\n\n fromList [ 1, 2, 3, 4 ] |> removeAt 2\n --> fromList [ 1, 2, 4 ]\n\n fromList [ 1, 2, 3, 4 ] |> removeAt -1\n --> fromList [ 1, 2, 3, 4 ]\n\n fromList [ 1, 2, 3, 4 ] |> removeAt 100\n --> fromList [ 1, 2, 3, 4 ]\n\n","type":"Basics.Int -> Array.Array element -> Array.Array element"},{"name":"removeWhen","comment":" Only keep elements which fail to satisfy a given predicate.\nThis is equivalent to `Array.filter (not << predicate)`.\n\n import Array exposing (fromList)\n\n fromList [ -1, 92, 0, 14, -3 ]\n |> removeWhen (\\x -> x < 0)\n --> fromList [ 92, 0, 14 ]\n\n","type":"(element -> Basics.Bool) -> Array.Array element -> Array.Array element"},{"name":"resizelIndexed","comment":" Resize from the left, padding the right-hand side with a given value based on index.\n\n import Array exposing (fromList, empty)\n\n fromList [ 'a', 'b', 'c' ]\n |> resizelIndexed 5 toLetterInAlphabet\n --> fromList [ 'a', 'b', 'c', 'd', 'e' ]\n\n fromList [ 'a', 'b', 'c' ]\n |> resizelIndexed 2 toLetterInAlphabet\n --> fromList [ 'a', 'b' ]\n\n fromList [ 'a', 'b', 'c' ]\n |> resizelIndexed -1 toLetterInAlphabet\n --> empty\n\n toLetterInAlphabet : Int -> Char\n toLetterInAlphabet inAlphabet =\n ('a' |> Char.toCode) + inAlphabet\n |> Char.fromCode\n\n","type":"Basics.Int -> (Basics.Int -> element) -> Array.Array element -> Array.Array element"},{"name":"resizelRepeat","comment":" Resize from the left, padding the right-hand side with a given value.\n\n import Array exposing (fromList, empty)\n\n fromList [ 1, 2 ] |> resizelRepeat 4 0\n --> fromList [ 1, 2, 0, 0 ]\n\n fromList [ 1, 2, 3 ] |> resizelRepeat 2 0\n --> fromList [ 1, 2 ]\n\n fromList [ 1, 2 ] |> resizelRepeat -1 0\n --> empty\n\n","type":"Basics.Int -> element -> Array.Array element -> Array.Array element"},{"name":"resizerIndexed","comment":" Resize from the right, padding the left-hand side with a given value based on index.\n\n import Array exposing (fromList, empty)\n\n fromList [ 10, 25, 36 ]\n |> resizerIndexed 5 (\\n -> n * 5)\n --> fromList [ 0, 5, 10, 25, 36 ]\n\n fromList [ 10, 25, 36 ]\n |> resizerIndexed 2 (\\n -> n * 5)\n --> fromList [ 25, 36 ]\n\n fromList [ 10, 25, 36 ]\n |> resizerIndexed -1 (\\n -> n * 5)\n --> empty\n\n","type":"Basics.Int -> (Basics.Int -> element) -> Array.Array element -> Array.Array element"},{"name":"resizerRepeat","comment":" Resize from the right, padding the left-hand side with a given value.\n\n import Array exposing (fromList, empty)\n\n fromList [ 1, 2 ] |> resizerRepeat 4 0\n --> fromList [ 0, 0, 1, 2 ]\n\n fromList [ 1, 2, 3 ] |> resizerRepeat 2 0\n --> fromList [ 2, 3 ]\n\n fromList [ 1, 2 ] |> resizerRepeat -1 0\n --> empty\n\n","type":"Basics.Int -> element -> Array.Array element -> Array.Array element"},{"name":"reverse","comment":" Flip the element order.\n\n import Array exposing (fromList)\n\n fromList [ 1, 2, 3, 4 ] |> reverse\n --> fromList [ 4, 3, 2, 1 ]\n\n","type":"Array.Array element -> Array.Array element"},{"name":"sliceFrom","comment":" Drop a given number of elements from the start.\nIn other words, slice the `Array` from an index until the very end.\nGiven a negative argument, count the end of the slice from the end.\n\n import Array exposing (fromList)\n\n fromList (List.range 0 6) |> sliceFrom 3\n --> fromList [ 3, 4, 5, 6 ]\n\n fromList (List.range 0 6) |> sliceFrom -3\n --> fromList [ 4, 5, 6 ]\n\n","type":"Basics.Int -> Array.Array a -> Array.Array a"},{"name":"sliceUntil","comment":" Take a number of elements from the start.\nIn other words, slice the `Array` from the very beginning until not including the index.\nGiven a negative argument, count the beginning of the slice from the end.\n\n import Array exposing (fromList)\n\n fromList (List.range 0 6) |> sliceUntil 3\n --> fromList [ 0, 1, 2 ]\n\n fromList (List.range 0 6) |> sliceUntil -3\n --> fromList [ 0, 1, 2, 3 ]\n\n","type":"Basics.Int -> Array.Array a -> Array.Array a"},{"name":"splitAt","comment":" Split into two `Array`s, the first ending before and the second starting with a given index.\n\n import Array exposing (fromList, empty)\n\n fromList [ 1, 2, 3, 4 ] |> splitAt 2\n --> ( fromList [ 1, 2 ], fromList [ 3, 4 ] )\n\n fromList [ 1, 2, 3, 4 ] |> splitAt 100\n --> ( fromList [ 1, 2, 3, 4 ], empty )\n\n fromList [ 1, 2, 3, 4 ] |> splitAt -1\n --> ( empty, fromList [ 1, 2, 3, 4 ] )\n\n","type":"Basics.Int -> Array.Array element -> ( Array.Array element, Array.Array element )"},{"name":"unzip","comment":" Split all tuple elements into a tuple of one `Array` with the first and one with the second values.\n\n import Array exposing (fromList)\n\n unzip\n (fromList\n [ ( 1, 'a' ), ( 2, 'b' ), ( 3, 'c' ) ]\n )\n --> ( fromList [ 1, 2, 3 ]\n --> , fromList [ 'a', 'b', 'c' ]\n --> )\n\n","type":"Array.Array ( elementFirst, elementSecond ) -> ( Array.Array elementFirst, Array.Array elementSecond )"},{"name":"update","comment":" Update the element at a given index based on its current value.\nIf the index is out of bounds, nothing is changed.\n\n import Array exposing (fromList)\n\n fromList [ 1, 2, 3 ] |> update 1 (\\n -> n + 10)\n --> fromList [ 1, 12, 3 ]\n\n fromList [ 1, 2, 3 ] |> update 4 (\\n -> n + 10)\n --> fromList [ 1, 2, 3 ]\n\n fromList [ 1, 2, 3 ] |> update -1 (\\n -> n + 10)\n --> fromList [ 1, 2, 3 ]\n\n","type":"Basics.Int -> (a -> a) -> Array.Array a -> Array.Array a"},{"name":"zip","comment":" Combine the elements of two `Array`s into tuples.\nIf one is longer, its extra elements are not used.\n\n import Array exposing (fromList)\n\n zip\n (fromList [ 1, 2, 3 ])\n (fromList [ 'a', 'b' ])\n --> fromList [ ( 1, 'a' ), ( 2, 'b' ) ]\n\n","type":"Array.Array firstElement -> Array.Array secondElement -> Array.Array ( firstElement, secondElement )"},{"name":"zip3","comment":" Zip the elements of three `Array`s into 3-tuples.\nOnly the indexes of the shortest `Array` are used.\n\n import Array exposing (fromList)\n\n zip3\n (fromList [ 1, 2, 3 ])\n (fromList [ 'a', 'b' ])\n (fromList [ \"a\", \"b\", \"c\", \"d\" ])\n --> fromList\n --> [ ( 1, 'a', \"a\" )\n --> , ( 2, 'b', \"b\" )\n --> ]\n\n","type":"Array.Array firstElement -> Array.Array secondElement -> Array.Array thirdElement -> Array.Array ( firstElement, secondElement, thirdElement )"}],"binops":[]},{"name":"Basics.Extra","comment":" Additional basic functions.\n\n\n# Tuples\n\n@docs swap\n\n\n# Numbers\n\n@docs maxSafeInteger, minSafeInteger, isSafeInteger\n\n\n# Math\n\n@docs atMost, atLeast\n@docs safeDivide, safeIntegerDivide\n@docs safeModBy, safeRemainderBy, fractionalModBy\n\n\n# Angles\n\n@docs inDegrees, inRadians, inTurns\n\n\n# Higher-Order Helpers\n\n@docs flip, curry, uncurry\n\n\n# Comparison & Ordering\n\n@docs orderBy, toOrder, toOrderDesc\n\n","unions":[],"aliases":[],"values":[{"name":"atLeast","comment":" Defines a lower bound for a variable.\n\n -42 |> atLeast 0 --> 0\n\n 42 |> atLeast 0 --> 42\n\n","type":"comparable -> comparable -> comparable"},{"name":"atMost","comment":" Defines an upper bound for a variable.\n\n 42 |> atMost 0 --> 0\n\n -42 |> atMost 0 --> -42\n\n","type":"comparable -> comparable -> comparable"},{"name":"curry","comment":" Change how arguments are passed to a function.\nThis splits paired arguments into two separate arguments.\n","type":"(( a, b ) -> c) -> a -> b -> c"},{"name":"flip","comment":" Flip the order of the first two arguments to a function.\n","type":"(a -> b -> c) -> b -> a -> c"},{"name":"fractionalModBy","comment":" Perform [modular arithmetic](https://en.wikipedia.org/wiki/Modular_arithmetic)\ninvolving floating point numbers.\n\nThe sign of the result is the same as the sign of the `modulus`\nin `fractionalModBy modulus x`.\n\n fractionalModBy 2.5 5 --> 0\n\n fractionalModBy 2 4.5 == 0.5\n\n fractionalModBy 2 -4.5 == 1.5\n\n fractionalModBy -2 4.5 == -1.5\n\n","type":"Basics.Float -> Basics.Float -> Basics.Float"},{"name":"inDegrees","comment":" Convert standard Elm angles (radians) to degrees.\n\n inDegrees (turns 2) --> 720\n\n inDegrees pi --> 180\n\n","type":"Basics.Float -> Basics.Float"},{"name":"inRadians","comment":" Convert standard Elm angles (radians) to radians.\n\n inRadians (degrees 90) == pi / 2\n\n inRadians (turns 1) == 2 * pi\n\n","type":"Basics.Float -> Basics.Float"},{"name":"inTurns","comment":" Convert standard Elm angles (radians) to turns. One turn is equal to 360°.\n\n inTurns (degrees 180) == 0.5\n\n inTurns (3 * pi) == 1.5\n\n","type":"Basics.Float -> Basics.Float"},{"name":"isSafeInteger","comment":" Checks if a given integer is within the safe range, meaning it is between\n`-(2^53 - 1)` and `2^53 - 1`.\n\n isSafeInteger 5 --> True\n\n isSafeInteger maxSafeInteger --> True\n\n isSafeInteger (maxSafeInteger + 1) --> False\n\n","type":"Basics.Int -> Basics.Bool"},{"name":"maxSafeInteger","comment":" The maximum _safe_ value for an integer, defined as `2^53 - 1`. Anything\nlarger than that and behaviour becomes mathematically unsound.\n\n maxSafeInteger + 1 --> maxSafeInteger + 2\n\n","type":"number"},{"name":"minSafeInteger","comment":" The minimum _safe_ value for an integer, defined as `-(2^53 - 1)`. Anything\nsmaller than that, and behaviour becomes mathematically unsound.\n\n minSafeInteger - 1 --> minSafeInteger - 2\n\n","type":"number"},{"name":"orderBy","comment":" Create an ordering function that can be used to sort\nlists by multiple dimensions, by flattening multiple ordering functions into one.\n\nThis is equivalent to `ORDER BY` in SQL. The ordering function will order\nits inputs based on the order that they appear in the `List (a -> a -> Order)` argument.\n\n type alias Pen =\n { model : String\n , tipWidthInMillimeters : Float\n }\n\n pens : List Pen\n pens =\n [ Pen \"Pilot Hi-Tec-C Gel\" 0.4\n , Pen \"Morning Glory Pro Mach\" 0.38\n , Pen \"Pilot Hi-Tec-C Coleto\" 0.5\n ]\n\n order : Pen -> Pen -> Order\n order =\n orderBy [ toOrder .tipWidthInMillimeters, toOrder .model ]\n\n List.sortWith order pens\n --> [ Pen \"Morning Glory Pro Mach\" 0.38\n --> , Pen \"Pilot Hi-Tec-C Gel\" 0.4\n --> , Pen \"Pilot Hi-Tec-C Coleto\" 0.5\n --> ]\n\nIf our `Pen` type alias above was represented a row in a database table, our `order` function as defined above would be equivalent\nto this SQL clause:\n\n ORDER BY tipWidthInMillimeters, model\n\n","type":"List.List (a -> a -> Basics.Order) -> a -> a -> Basics.Order"},{"name":"safeDivide","comment":" Perform floating-point division (like Elm's `/` operator) that will never\ncrash the app. If the `y` argument in `safeDivide x y` is zero, we return `Nothing`.\n\n safeDivide 5 2 --> Just 2.5\n\n -- the interesting part\n safeDivide 5 0 --> Nothing\n\n","type":"Basics.Float -> Basics.Float -> Maybe.Maybe Basics.Float"},{"name":"safeIntegerDivide","comment":" Perform integer division (like Elm's `//` operator) that will never crash\nthe app. If the `y` argument in `safeIntegerDivide x y` is zero, we return `Nothing`.\n\n safeIntegerDivide 5 2 --> Just 2\n\n -- the interesting part\n safeIntegerDivide 5 0 --> Nothing\n\n","type":"Basics.Int -> Basics.Int -> Maybe.Maybe Basics.Int"},{"name":"safeModBy","comment":" Perform [modular arithmetic][ma] that will never crash the app. If the `modulus`\nargument in `safeModBy modulus x` is zero, we return `Nothing`.\n\n safeModBy 2 4 --> Just 0\n\n safeModBy 2 5 --> Just 1\n\n -- the interesting part\n safeModBy 0 4 --> Nothing\n\nUse [`safeRemainderBy`](#safeRemainderBy) for a different treatment of negative\nnumbers, or read Daan Leijen’s [Division and Modulus for Computer Scientists][dm]\nfor more information.\n\n[ma]: https://en.wikipedia.org/wiki/Modular_arithmetic\n[dm]: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf\n\n","type":"Basics.Int -> Basics.Int -> Maybe.Maybe Basics.Int"},{"name":"safeRemainderBy","comment":" Get the remainder after division in a way that will never crash the app. If\nthe `divisor` argument in `safeRemainderBy divisor x` is zero, we return `Nothing`.\n\n safeRemainderBy 2 4 --> Just 0\n\n safeRemainderBy 2 5 --> Just 1\n\n -- the interesting part\n safeRemainderBy 0 4 --> Nothing\n\nUse [`safeModBy`](#safeModBy) for a different treatment of negative\nnumbers, or read Daan Leijen’s [Division and Modulus for Computer Scientists][dm]\nfor more information.\n\n[dm]: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf\n\n","type":"Basics.Int -> Basics.Int -> Maybe.Maybe Basics.Int"},{"name":"swap","comment":" Swaps the elements in a pair.\n\n swap ( 1, 2 ) --> ( 2, 1 )\n\n","type":"( a, b ) -> ( b, a )"},{"name":"toOrder","comment":" Helper for multi-dimensional sort.\n\nTakes a function that extracts a comparable value from a type `a` as a key,\nand returns a function `a -> a -> Order`.\n\nThis is primarily a helper function for the `orderBy` function above.\n\n {- Simple example: wrapping a function that turns\n a custom type into an instance of `comparable`\n -}\n\n type Color\n = Red\n | Yellow\n | Green\n\n colorToComparable : Color -> Int\n colorToComparable light =\n case light of\n Red -> 0\n Yellow -> 1\n Green -> 2\n\n colorToOrder : Color -> Color -> Order\n colorToOrder =\n toOrder colorToComparable\n\n List.sortWith\n colorToOrder\n [ Yellow, Yellow, Red, Green, Red ]\n --> [ Red, Red, Yellow, Yellow, Green ]\n\n\n {- More interesting example: using the property accessor\n methods on a custom type with `toOrder`; we only need\n this function when we want to combine multiple ordering functions into one.\n -}\n\n type alias Light =\n { color : Color\n , action : String\n , timeActivatedSeconds : Float\n }\n\n lights : List Light\n lights =\n [ Light Green \"Go\" 60\n , Light Yellow \"Slow down\" 5.5\n , Light Red \"Stop\" 60\n ]\n\n List.sortWith\n ( orderBy\n [ toOrder .timeActivatedSeconds\n , toOrder (.color >> colorToComparable)\n ]\n )\n lights\n --> [ Light Yellow \"Slow down\" 5.5\n --> , Light Red \"Stop\" 60\n --> , Light Green \"Go\" 60\n --> ]\n\n(Note that `List.sortWith colorOrder` above is identical to `List.sortBy colorToComparable`.)\n\n","type":"(a -> comparable) -> a -> a -> Basics.Order"},{"name":"toOrderDesc","comment":" Same as `toOrder`, with flipped comparisons to enable \"sort by descending\".\n\n type Color\n = Red\n | Yellow\n | Green\n\n colorToComparable : Color -> Int\n colorToComparable light =\n case light of\n Red -> 0\n Yellow -> 1\n Green -> 2\n\n colorToOrder : Color -> Color -> Order\n colorToOrder =\n toOrderDesc colorToComparable\n\n List.sortWith\n colorToOrder\n [ Yellow, Yellow, Red, Green, Red ]\n --> [ Green, Yellow, Yellow, Red, Red ]\n\n","type":"(a -> comparable) -> a -> a -> Basics.Order"},{"name":"uncurry","comment":" Change how arguments are passed to a function.\nThis combines two arguments into a single pair.\n","type":"(a -> b -> c) -> ( a, b ) -> c"}],"binops":[]},{"name":"Dict.Extra","comment":" Convenience functions for working with `Dict`\n\n\n# List operations\n\n@docs groupBy, filterGroupBy, fromListBy, fromListDedupe, fromListDedupeBy, frequencies\n\n\n# Manipulation\n\n@docs removeWhen, removeMany, keepOnly, insertDedupe, mapKeys, filterMap, invert\n\n\n# Utilities\n\n@docs any, find\n\n","unions":[],"aliases":[],"values":[{"name":"any","comment":" Determine if any key/value pair satisfies some test.\n\n import Dict\n\n Dict.fromList [ ( 9, \"Jill\" ), ( 7, \"Jill\" ) ]\n |> any (\\_ value -> value == \"Jill\")\n --> True\n\n Dict.fromList [ ( 9, \"Jill\" ), ( 7, \"Jill\" ) ]\n |> any (\\key _ -> key == 5)\n --> False\n\n","type":"(comparable -> a -> Basics.Bool) -> Dict.Dict comparable a -> Basics.Bool"},{"name":"filterGroupBy","comment":" Takes a key-fn and a list.\nCreates a `Dict` which maps the key to a list of matching elements, skipping elements\nwhere key-fn returns `Nothing`\n\n import Dict\n\n filterGroupBy (String.uncons >> Maybe.map Tuple.first) [ \"tree\" , \"\", \"tweet\", \"apple\" , \"leaf\", \"\" ]\n --> Dict.fromList [ ( 't', [ \"tree\", \"tweet\" ] ), ( 'a', [ \"apple\" ] ), ( 'l', [ \"leaf\" ] ) ]\n\n filterGroupBy\n .car\n [ { name = \"Mary\"\n , car = Just \"Ford\"\n }\n , { name = \"Jack\"\n , car = Nothing\n }\n , { name = \"Jill\"\n , car = Just \"Tesla\"\n }\n , { name = \"John\"\n , car = Just \"Tesla\"\n }\n ]\n --> Dict.fromList\n --> [ ( \"Ford\"\n --> , [ { name = \"Mary\" , car = Just \"Ford\" } ]\n --> )\n --> , ( \"Tesla\"\n --> , [ { name = \"Jill\" , car = Just \"Tesla\" }\n --> , { name = \"John\" , car = Just \"Tesla\" }\n --> ]\n --> )\n --> ]\n\n","type":"(a -> Maybe.Maybe comparable) -> List.List a -> Dict.Dict comparable (List.List a)"},{"name":"filterMap","comment":" Apply a function that may or may not succeed to all entries in a dictionary,\nbut only keep the successes.\n\n import Dict\n\n let\n isTeen n a =\n if 13 <= n && n <= 19 then\n Just <| String.toUpper a\n else\n Nothing\n in\n Dict.fromList [ ( 5, \"Jack\" ), ( 15, \"Jill\" ), ( 20, \"Jones\" ) ]\n |> filterMap isTeen\n --> Dict.fromList [ ( 15, \"JILL\" ) ]\n\n","type":"(comparable -> a -> Maybe.Maybe b) -> Dict.Dict comparable a -> Dict.Dict comparable b"},{"name":"find","comment":" Find the first key/value pair that matches a predicate.\n\n import Dict\n\n Dict.fromList [ ( 9, \"Jill\" ), ( 7, \"Jill\" ) ]\n |> find (\\_ value -> value == \"Jill\")\n --> Just ( 7, \"Jill\" )\n\n Dict.fromList [ ( 9, \"Jill\" ), ( 7, \"Jill\" ) ]\n |> find (\\key _ -> key == 5)\n --> Nothing\n\n","type":"(comparable -> a -> Basics.Bool) -> Dict.Dict comparable a -> Maybe.Maybe ( comparable, a )"},{"name":"frequencies","comment":" Count the number of occurences for each of the elements in the list.\n\n import Dict\n\n frequencies [ \"A\", \"B\", \"C\", \"B\", \"C\", \"B\" ]\n --> Dict.fromList [ ( \"A\", 1 ), ( \"B\", 3 ), ( \"C\", 2 ) ]\n\n","type":"List.List comparable -> Dict.Dict comparable Basics.Int"},{"name":"fromListBy","comment":" Create a dictionary from a list of values, by passing a function that can get a key from any such value.\nIf the function does not return unique keys, earlier values are discarded.\n\n import Dict\n\n fromListBy String.length [ \"tree\" , \"apple\" , \"leaf\" ]\n --> Dict.fromList [ ( 4, \"leaf\" ), ( 5, \"apple\" ) ]\n\n","type":"(a -> comparable) -> List.List a -> Dict.Dict comparable a"},{"name":"fromListDedupe","comment":" Like `Dict.fromList`, but you provide a way to deal with\nduplicate keys. Create a dictionary from a list of pairs of keys and\nvalues, providing a function that is used to combine multiple values\npaired with the same key.\n\n import Dict\n\n fromListDedupe\n (\\a b -> a ++ \" \" ++ b)\n [ ( \"class\", \"menu\" ), ( \"width\", \"100%\" ), ( \"class\", \"big\" ) ]\n --> Dict.fromList [ ( \"class\", \"menu big\" ), ( \"width\", \"100%\" ) ]\n\n","type":"(a -> a -> a) -> List.List ( comparable, a ) -> Dict.Dict comparable a"},{"name":"fromListDedupeBy","comment":" `fromListBy` and `fromListDedupe` rolled into one.\n\n import Dict\n\n fromListDedupeBy (\\first second -> first) String.length [ \"tree\" , \"apple\" , \"leaf\" ]\n --> Dict.fromList [ ( 4, \"tree\" ), ( 5, \"apple\" ) ]\n\n","type":"(a -> a -> a) -> (a -> comparable) -> List.List a -> Dict.Dict comparable a"},{"name":"groupBy","comment":" Takes a key-fn and a list.\nCreates a `Dict` which maps the key to a list of matching elements.\n\n import Dict\n\n groupBy String.length [ \"tree\" , \"apple\" , \"leaf\" ]\n --> Dict.fromList [ ( 4, [ \"tree\", \"leaf\" ] ), ( 5, [ \"apple\" ] ) ]\n\n","type":"(a -> comparable) -> List.List a -> Dict.Dict comparable (List.List a)"},{"name":"insertDedupe","comment":" Insert an element at the given key, providing a combining\nfunction that used in the case that there is already an\nelement at that key. The combining function is called with\noriginal element and the new element as arguments and\nreturns the element to be inserted.\n\n import Dict\n\n Dict.fromList [ ( \"expenses\", 38.25 ), ( \"assets\", 100.85 ) ]\n |> insertDedupe (+) \"expenses\" 2.50\n |> insertDedupe (+) \"liabilities\" -2.50\n --> Dict.fromList [ ( \"expenses\", 40.75 ), ( \"assets\", 100.85 ), ( \"liabilities\", -2.50 ) ]\n\n","type":"(v -> v -> v) -> comparable -> v -> Dict.Dict comparable v -> Dict.Dict comparable v"},{"name":"invert","comment":" Inverts the keys and values of an array.\n\n import Dict\n\n Dict.fromList [ (\"key\", \"value\") ]\n |> invert\n --> Dict.fromList [ ( \"value\", \"key\" ) ]\n\n","type":"Dict.Dict comparable1 comparable2 -> Dict.Dict comparable2 comparable1"},{"name":"keepOnly","comment":" Keep a key-value pair if its key appears in the set.\n\n import Dict\n import Set\n\n Dict.fromList [ ( \"Mary\", 1 ), ( \"Jack\", 2 ), ( \"Jill\", 1 ) ]\n |> keepOnly (Set.fromList [ \"Jack\", \"Jill\" ])\n --> Dict.fromList [ ( \"Jack\", 2 ), ( \"Jill\", 1 ) ]\n\n","type":"Set.Set comparable -> Dict.Dict comparable v -> Dict.Dict comparable v"},{"name":"mapKeys","comment":" Apply a function to all keys in a dictionary.\n\n import Dict\n\n Dict.fromList [ ( 5, \"Jack\" ), ( 10, \"Jill\" ) ]\n |> mapKeys (\\x -> x + 1)\n --> Dict.fromList [ ( 6, \"Jack\" ), ( 11, \"Jill\" ) ]\n\n Dict.fromList [ ( 5, \"Jack\" ), ( 10, \"Jill\" ) ]\n |> mapKeys String.fromInt\n --> Dict.fromList [ ( \"5\", \"Jack\" ), ( \"10\", \"Jill\" ) ]\n\n","type":"(comparable -> comparable1) -> Dict.Dict comparable v -> Dict.Dict comparable1 v"},{"name":"removeMany","comment":" Remove a key-value pair if its key appears in the set.\n\n import Dict\n import Set\n\n Dict.fromList [ ( \"Mary\", 1 ), ( \"Jack\", 2 ), ( \"Jill\", 1 ) ]\n |> removeMany (Set.fromList [ \"Mary\", \"Jill\" ])\n --> Dict.fromList [ ( \"Jack\", 2 ) ]\n\n","type":"Set.Set comparable -> Dict.Dict comparable v -> Dict.Dict comparable v"},{"name":"removeWhen","comment":" Remove elements which satisfies the predicate.\n\n import Dict\n\n Dict.fromList [ ( \"Mary\", 1 ), ( \"Jack\", 2 ), ( \"Jill\", 1 ) ]\n |> removeWhen (\\_ value -> value == 1 )\n --> Dict.fromList [ ( \"Jack\", 2 ) ]\n\n","type":"(comparable -> v -> Basics.Bool) -> Dict.Dict comparable v -> Dict.Dict comparable v"}],"binops":[]},{"name":"List.Extra","comment":" Convenience functions for working with List\n\n\n# Basics\n\n@docs last, init, getAt, uncons, unconsLast, maximumBy, maximumWith, minimumBy, minimumWith, andMap, andThen, reverseMap, reverseFilter, takeWhile, dropWhile, unique, uniqueBy, allDifferent, allDifferentBy, setIf, setAt, remove, updateIf, updateAt, updateIfIndex, removeAt, removeIfIndex, filterNot, swapAt, stableSortWith\n\n\n# List transformations\n\n@docs intercalate, transpose, subsequences, permutations, interweave, cartesianProduct, uniquePairs\n\n\n# Folds\n\n@docs foldl1, foldr1, indexedFoldl, indexedFoldr, Step, stoppableFoldl\n\n\n# Building lists\n\n@docs scanl, scanl1, scanr, scanr1, mapAccuml, mapAccumr, unfoldr, iterate, initialize, cycle, reverseRange\n\n\n# Sublists\n\n@docs splitAt, splitWhen, takeWhileRight, dropWhileRight, span, break, stripPrefix, group, groupWhile, inits, tails, select, selectSplit, gatherEquals, gatherEqualsBy, gatherWith, subsequencesNonEmpty, frequencies\n\n\n# Predicates\n\n@docs isPrefixOf, isSuffixOf, isInfixOf, isSubsequenceOf, isPermutationOf\n\n\n# Searching\n\n@docs notMember, find, elemIndex, elemIndices, findIndex, findIndices, findMap, count\n\n\n# Zipping\n\n@docs zip, zip3\n\n\n# Lift functions onto multiple lists of arguments\n\n@docs lift2, lift3, lift4\n\n\n# Split to groups of given size\n\n@docs groupsOf, groupsOfWithStep, groupsOfVarying, greedyGroupsOf, greedyGroupsOfWithStep\n\n\n# Joins\n\n@docs joinOn\n\n","unions":[{"name":"Step","comment":" A custom type used for stoppable folds.\n","args":["a"],"cases":[["Continue",["a"]],["Stop",["a"]]]}],"aliases":[],"values":[{"name":"allDifferent","comment":" Indicate if list has duplicate values.\n\n allDifferent [ 0, 1, 1, 0, 1 ]\n --> False\n\n allDifferent [ 0, 1, 2]\n --> True\n\n","type":"List.List a -> Basics.Bool"},{"name":"allDifferentBy","comment":" Indicate if list has duplicate values when supplied function are applied on each values.\n","type":"(a -> b) -> List.List a -> Basics.Bool"},{"name":"andMap","comment":" Map functions taking multiple arguments over multiple lists. Each list should be of the same length.\n\n toIntFunctions : List (Float -> Int)\n toIntFunctions =\n [ round\n , floor\n , ceiling\n , truncate\n ]\n\n toIntFunctions\n |> andMap [ -1.5, -1.5, -1.5, -1.5 ]\n --> [ -1, -2, -1, -1 ]\n\n\n math : List (Int -> Int)\n math =\n [ (+) 1\n , (*) 2\n , (*) 3 >> (+) 1\n ]\n\n math\n |> andMap [ 1, 2, 3 ]\n --> [ 2, 4, 10 ]\n\n","type":"List.List a -> List.List (a -> b) -> List.List b"},{"name":"andThen","comment":" Equivalent to `concatMap`. For example, suppose you want to have a cartesian product of [1,2] and [3,4]:\n\n [ 1, 2 ]\n |> andThen\n (\\x ->\n [ 3, 4 ]\n |> andThen (\\y -> [ ( x, y ) ])\n )\n --> [ ( 1, 3 ), ( 1, 4 ), ( 2, 3 ), ( 2, 4 ) ]\n\nNow suppose we want to have a cartesian product between the first list and the second list and its doubles:\n\n [ 1, 2 ]\n |> andThen\n (\\x ->\n [ 3, 4 ]\n |> andThen\n (\\y ->\n [ y, y * 2 ]\n |> andThen (\\z -> [ ( x, z ) ])\n )\n )\n --> [ ( 1, 3 ), ( 1, 6 ), ( 1, 4 ), ( 1, 8 ), ( 2, 3 ), ( 2, 6 ), ( 2, 4 ), ( 2, 8 )]\n\nAdvanced functional programmers will recognize this as the implementation of bind operator (>>=) for lists from the `Monad` typeclass.\n\n","type":"(a -> List.List b) -> List.List a -> List.List b"},{"name":"break","comment":" Take a predicate and a list, return a tuple. The first part of the tuple is the longest prefix of that list, for each element of which the predicate _does not_ hold. The second part of the tuple is the remainder of the list. `break p xs` is equivalent to `(takeWhile (not p) xs, dropWhile (not p) xs)`.\n\n break ((<) 3) [ 1, 2, 3, 4, 1, 2, 3, 4 ]\n --> ( [ 1, 2, 3 ], [ 4, 1, 2, 3, 4 ] )\n\n break ((>) 5) [ 1, 2, 3 ]\n --> ( [], [ 1, 2, 3 ] )\n\n break ((<) 5) [ 1, 2, 3 ]\n --> ( [ 1, 2, 3 ], [] )\n\n","type":"(a -> Basics.Bool) -> List.List a -> ( List.List a, List.List a )"},{"name":"cartesianProduct","comment":" Return the cartesian product of a list of lists.\nIf one list is empty, the result is an empty list.\nIf the list of lists is empty, the result is an empty singleton.\n\n cartesianProduct [ [ 1, 2 ], [ 3, 4, 5 ], [ 6 ] ]\n --> [ [ 1, 3, 6 ], [ 1, 4, 6 ], [ 1, 5, 6 ], [ 2, 3, 6 ], [ 2, 4, 6 ], [ 2, 5, 6 ] ]\n\n cartesianProduct [ [ 1, 2 ] ]\n --> [ [ 1 ], [ 2 ] ]\n\n cartesianProduct [ [ 1, 2 ], [], [ 6 ] ]\n --> []\n\n cartesianProduct [ [] ]\n --> []\n\n cartesianProduct []\n --> [ [] ]\n\n","type":"List.List (List.List a) -> List.List (List.List a)"},{"name":"count","comment":" Returns the number of elements in a list that satisfy a given predicate.\nEquivalent to `List.length (List.filter pred list)` but more efficient.\n\n count\n (modBy 2 >> (==) 1) [ 1, 2, 3, 4, 5, 6, 7 ]\n --> 4\n\n count\n ((==) \"yeah\")\n [ \"She\", \"loves\", \"you\", \"yeah\", \"yeah\", \"yeah\" ]\n --> 3\n\n","type":"(a -> Basics.Bool) -> List.List a -> Basics.Int"},{"name":"cycle","comment":" Creates a list of the given length whose elements are obtained by cycling\nthrough the elements of the given list. If the given list is empty, the\nresulting list will be empty.\n\n cycle 6 [ 4, 7, 8 ]\n --> [ 4, 7, 8, 4, 7, 8 ]\n\n cycle 4 [ 'a', 'b', 'c' ]\n --> [ 'a', 'b', 'c', 'a' ]\n\n cycle 9001 []\n --> []\n\n cycle 2 [ 1, 2, 3, 4, 5 ]\n --> [ 1, 2 ]\n\n","type":"Basics.Int -> List.List a -> List.List a"},{"name":"dropWhile","comment":" Drop elements in order as long as the predicate evaluates to `True`\n","type":"(a -> Basics.Bool) -> List.List a -> List.List a"},{"name":"dropWhileRight","comment":" Drop elements from the right, while predicate still holds.\n\n dropWhileRight ((<) 5) (List.range 1 10)\n --> [ 1, 2, 3, 4, 5 ]\n\n","type":"(a -> Basics.Bool) -> List.List a -> List.List a"},{"name":"elemIndex","comment":" Return the index of the first occurrence of the element. Otherwise, return `Nothing`. Indexing starts from 0.\n\n elemIndex 1 [ 1, 2, 3 ]\n --> Just 0\n\n elemIndex 4 [ 1, 2, 3 ]\n --> Nothing\n\n elemIndex 1 [ 1, 2, 1 ]\n --> Just 0\n\n","type":"a -> List.List a -> Maybe.Maybe Basics.Int"},{"name":"elemIndices","comment":" Return all indices of occurrences of the element. If element is not found, return empty list. Indexing starts from 0.\n\n elemIndices 1 [ 1, 2, 3 ]\n --> [ 0 ]\n\n elemIndices 4 [ 1, 2, 3 ]\n --> []\n\n elemIndices 1 [ 1, 2, 1 ]\n --> [ 0, 2 ]\n\n","type":"a -> List.List a -> List.List Basics.Int"},{"name":"filterNot","comment":" Take a predicate and a list, and return a list that contains elements which fails to satisfy the predicate.\nThis is equivalent to `List.filter (not << predicate) list`.\n\n isEven : Int -> Bool\n isEven i =\n modBy 2 i == 0\n\n filterNot isEven [ 1, 2, 3, 4 ]\n --> [ 1, 3 ]\n\n","type":"(a -> Basics.Bool) -> List.List a -> List.List a"},{"name":"find","comment":" Find the first element that satisfies a predicate and return\nJust that element. If none match, return Nothing.\n\n find (\\num -> num > 5) [ 2, 4, 6, 8 ]\n --> Just 6\n\n","type":"(a -> Basics.Bool) -> List.List a -> Maybe.Maybe a"},{"name":"findIndex","comment":" Take a predicate and a list, return the index of the first element that satisfies the predicate. Otherwise, return `Nothing`. Indexing starts from 0.\n\n isEven : Int -> Bool\n isEven i =\n modBy 2 i == 0\n\n findIndex isEven [ 1, 2, 3 ]\n --> Just 1\n\n findIndex isEven [ 1, 3, 5 ]\n --> Nothing\n\n findIndex isEven [ 1, 2, 4 ]\n --> Just 1\n\n","type":"(a -> Basics.Bool) -> List.List a -> Maybe.Maybe Basics.Int"},{"name":"findIndices","comment":" Take a predicate and a list, return indices of all elements satisfying the predicate. Otherwise, return empty list. Indexing starts from 0.\n\n isEven : Int -> Bool\n isEven i =\n modBy 2 i == 0\n\n findIndices isEven [ 1, 2, 3 ]\n --> [ 1 ]\n\n findIndices isEven [ 1, 3, 5 ]\n --> []\n\n findIndices isEven [ 1, 2, 4 ]\n --> [ 1, 2 ]\n\n","type":"(a -> Basics.Bool) -> List.List a -> List.List Basics.Int"},{"name":"findMap","comment":" Apply a function that may succeed to values in the list and return the result of the first successful match. If none match, then return Nothing.\n\n mapOverFive : Int -> Maybe Int\n mapOverFive num =\n if num > 5 then\n Just (num * 2)\n else\n Nothing\n\n findMap mapOverFive [2, 4, 6, 8]\n --> Just 12\n\nThis is particularly useful in cases where you have a complex type in a list, and you need to pick out the the first one\n\n type alias HouseModel =\n {}\n\n type Property\n = Rental\n | House HouseModel\n | Commercial\n\n toHouse : Property -> Maybe HouseModel\n toHouse property =\n case property of\n House house ->\n Just house\n\n _ ->\n Nothing\n\n viewFirstHomeOfInterest : Viewer -> List Property -> Html msg\n viewFirstHomeOfInterest viewer propertiesQuery =\n propertiesQuery\n |> findMap toHouse\n |> Maybe.map homeView\n |> Maybe.withDefault noHomeView\n\n","type":"(a -> Maybe.Maybe b) -> List.List a -> Maybe.Maybe b"},{"name":"foldl1","comment":" Variant of `foldl` that has no starting value argument and treats the head of the list as its starting value. If the list is empty, return `Nothing`.\n\n foldl1 (-) [ 1, 2, 3, 4 ]\n --> Just 2\n\n foldl1 (++) [ \"a\", \"b\", \"c\" ]\n --> Just \"cba\"\n\n foldl1 min []\n --> Nothing\n\n**Note:** This function changed in a major way between version 7.0.0 and 8.0.0 of this package. The function `foldl1` took in 7.0.0 was `b -> a -> b` consistent with the Haskell implementation of `foldl`, but now its `a -> b -> b`, consistent with `List.foldl`. This function behaves differently in a breaking way, even though its type signature is the same.\n\n","type":"(a -> a -> a) -> List.List a -> Maybe.Maybe a"},{"name":"foldr1","comment":" Variant of `foldr` that has no starting value argument and treats the last element of the list as its starting value. If the list is empty, return `Nothing`.\n\n foldr1 (-) [ 1, 2, 3, 4 ]\n --> Just -2\n\n foldr1 (++) [ \"a\", \"b\", \"c\" ]\n --> Just \"abc\"\n\n foldr1 min []\n --> Nothing\n\n","type":"(a -> a -> a) -> List.List a -> Maybe.Maybe a"},{"name":"frequencies","comment":" Calculate the number of occurences for each element in a list. Elements\nwill be ordered ascendingly, then grouped in a tuple with the number of\noccurences.\n\n frequencies [2,1,3,2,3,3]\n --> [(1,1),(2,2),(3,3)]\n\n","type":"List.List comparable -> List.List ( comparable, Basics.Int )"},{"name":"gatherEquals","comment":" Group equal elements together. This is different from `group` as each sublist\nwill contain _all_ equal elements of the original list. Elements will be grouped\nin the same order as they appear in the original list. The same applies to elements\nwithin each group.\n\n gatherEquals [1,2,1,3,2]\n --> [(1,[1]),(2,[2]),(3,[])]\n\n","type":"List.List a -> List.List ( a, List.List a )"},{"name":"gatherEqualsBy","comment":" Group equal elements together. A function is applied to each element of the list\nand then the equality check is performed against the results of that function evaluation.\nElements will be grouped in the same order as they appear in the original list. The\nsame applies to elements within each group.\n\n gatherEqualsBy .age [{age=25},{age=23},{age=25}]\n --> [({age=25},[{age=25}]),({age=23},[])]\n\n","type":"(a -> b) -> List.List a -> List.List ( a, List.List a )"},{"name":"gatherWith","comment":" Group equal elements together using a custom equality function. Elements will be\ngrouped in the same order as they appear in the original list. The same applies to\nelements within each group.\n\n gatherWith (==) [1,2,1,3,2]\n --> [(1,[1]),(2,[2]),(3,[])]\n\n","type":"(a -> a -> Basics.Bool) -> List.List a -> List.List ( a, List.List a )"},{"name":"getAt","comment":" Returns `Just` the element at the given index in the list,\nor `Nothing` if the index is out of range.\n","type":"Basics.Int -> List.List a -> Maybe.Maybe a"},{"name":"greedyGroupsOf","comment":" Greedily split list into groups of length `size`. The last group of\nelements will be included regardless of whether there are enough elements in\nthe list to completely fill it. This is equivalent to calling\n`greedyGroupsOfWithStep` with the same `size` and `step`.\n\n greedyGroupsOf 3 (List.range 1 10)\n --> [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ], [ 10 ] ]\n\n","type":"Basics.Int -> List.List a -> List.List (List.List a)"},{"name":"greedyGroupsOfWithStep","comment":" Greedily split list into groups of length `size` at offsets `step` apart.\nThe last group of elements will be included regardless of whether there are\nenough elements in the list to completely fill it. (See `groupsOfWithStep`\nfor the non-greedy version of this function).\n\n greedyGroupsOfWithStep 4 4 (List.range 1 10)\n --> [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9, 10 ] ]\n\n greedyGroupsOfWithStep 3 2 (List.range 1 6)\n --> [ [ 1, 2, 3 ], [ 3, 4, 5 ], [ 5, 6 ] ]\n\n greedyGroupsOfWithStep 3 6 (List.range 1 20)\n --> [ [ 1, 2, 3 ], [ 7, 8, 9 ], [ 13, 14, 15 ], [ 19, 20 ] ]\n\nIf `step == size`, every element will appear in exactly one group. If\n`step < size`, there will be an overlap between groups. If `step > size`, some\nelements will be skipped and not appear in any groups.\n\n","type":"Basics.Int -> Basics.Int -> List.List a -> List.List (List.List a)"},{"name":"group","comment":" Group similar elements together. `group` is equivalent to `groupWhile (==)`.\n\n group [ 1, 2, 2, 3, 3, 3, 2, 2, 1 ]\n --> [ (1, []), (2, [ 2 ]), (3, [ 3, 3 ]), (2, [ 2 ]), ( 1, []) ]\n\n","type":"List.List a -> List.List ( a, List.List a )"},{"name":"groupWhile","comment":" Group elements together, using a custom comparison test (`a -> a -> Bool`). Start a new group each time the comparison test doesn't hold for two adjacent elements.\n\n`groupWhile` uses a non-empty list type `(a, List a)` since groups necessarily must have at least one member since they are determined by comparing two members.\n\n groupWhile\n (==)\n [ 1, 2, 3 ]\n --> [ ( 1, [] ), ( 2, [] ), ( 3, [] ) ]\n\n groupWhile\n (<)\n [ 1, 2, 3, 2, 4, 1, 3, 2, 1 ]\n --> [ ( 1, [ 2, 3 ] ), ( 2, [ 4 ] ), ( 1, [ 3 ] ), ( 2, [] ), ( 1, [] ) ]\n\n groupWhile\n (\\a b -> a.id == b.id)\n [ { value = 4, id = 9 }, { value = 7, id = 2 }, { value = 1, id = 2 } ]\n --> [ ( { value = 4, id = 9 }, [] ), ( { value = 7, id = 2 }, [ { value = 1, id = 2 } ] ) ]\n\n**Note:**\nThe behavior of this function has changed between major versions 7 and 8. In version 7 there was `groupWhile` and `groupWhileTransitively`. The behavior of the two was almost identical, however the transitive function was closer to what users found intuitive about grouping. `groupWhileTransitively` has been deleted, and `groupWhile` has been replaced with the version 7s `groupWhileTransitively` behavior. Furthermore the group type was changed from `List a` to the non-empty list type `(a, List a)`. Sorry for any inconvenience this may cause.\n\n","type":"(a -> a -> Basics.Bool) -> List.List a -> List.List ( a, List.List a )"},{"name":"groupsOf","comment":" Split list into groups of length `size`. If there are not enough elements\nto completely fill the last group, it will not be included. This is equivalent\nto calling `groupsOfWithStep` with the same `size` and `step`.\n\n groupsOf 3 (List.range 1 10)\n --> [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ]\n\n","type":"Basics.Int -> List.List a -> List.List (List.List a)"},{"name":"groupsOfVarying","comment":" `groupsOfVarying ns` takes `n` elements from a list for each `n` in `ns`, splitting the list into variably sized segments\n\n groupsOfVarying [ 2, 3, 1 ] [ \"a\", \"b\", \"c\", \"d\", \"e\", \"f\" ]\n --> [ [ \"a\", \"b\" ], [ \"c\", \"d\", \"e\" ], [ \"f\" ] ]\n\n groupsOfVarying [ 2 ] [ \"a\", \"b\", \"c\", \"d\", \"e\", \"f\" ]\n --> [ [ \"a\", \"b\" ] ]\n\n groupsOfVarying [ 2, 3, 1, 5, 6 ] [ \"a\", \"b\", \"c\", \"d\", \"e\" ]\n --> [ [ \"a\", \"b\" ], [ \"c\", \"d\", \"e\" ] ]\n\n","type":"List.List Basics.Int -> List.List a -> List.List (List.List a)"},{"name":"groupsOfWithStep","comment":" Split list into groups of length `size` at offsets `step` apart. If there\nare not enough elements to completely fill the last group, it will not be\nincluded. (See `greedyGroupsOfWithStep` if you would like the last group to be\nincluded regardless.)\n\n groupsOfWithStep 4 4 (List.range 1 10)\n --> [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ] ]\n\n groupsOfWithStep 3 1 (List.range 1 5)\n --> [ [ 1, 2, 3 ], [ 2, 3, 4 ], [ 3, 4, 5 ] ]\n\n groupsOfWithStep 3 6 (List.range 1 20)\n --> [ [ 1, 2, 3 ], [ 7, 8, 9 ], [ 13, 14, 15 ] ]\n\nIf `step == size`, every element (except for perhaps the last few due to the\nnon-greedy behavior) will appear in exactly one group. If `step < size`, there\nwill be an overlap between groups. If `step > size`, some elements will be\nskipped and not appear in any groups.\n\n","type":"Basics.Int -> Basics.Int -> List.List a -> List.List (List.List a)"},{"name":"indexedFoldl","comment":" Variant of `foldl` that passes the index of the current element to the step function. `indexedFoldl` is to `List.foldl` as `List.indexedMap` is to `List.map`.\n","type":"(Basics.Int -> a -> b -> b) -> b -> List.List a -> b"},{"name":"indexedFoldr","comment":" Variant of `foldr` that passes the index of the current element to the step function. `indexedFoldr` is to `List.foldr` as `List.indexedMap` is to `List.map`.\n","type":"(Basics.Int -> a -> b -> b) -> b -> List.List a -> b"},{"name":"init","comment":" Return all elements of the list except the last one.\n\n init [ 1, 2, 3 ]\n --> Just [ 1, 2 ]\n\n init []\n --> Nothing\n\n","type":"List.List a -> Maybe.Maybe (List.List a)"},{"name":"initialize","comment":" Initialize a list of some length with some function.\n\n`initialize n f` creates a list of length `n` with the element at index `i` initialized to the result of `f i`.\n\n","type":"Basics.Int -> (Basics.Int -> a) -> List.List a"},{"name":"inits","comment":" Return all initial segments of a list, from shortest to longest, empty list first, the list itself last.\n\n inits [ 1, 2, 3 ]\n --> [ [], [ 1 ], [ 1, 2 ], [ 1, 2, 3 ] ]\n\n","type":"List.List a -> List.List (List.List a)"},{"name":"intercalate","comment":" Take a list and a list of lists, insert that list between every list in the list of lists, concatenate the result. `intercalate xs xss` is equivalent to `concat (intersperse xs xss)`.\n\n intercalate [ 0, 0 ] [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ] ]\n --> [ 1, 2, 0, 0, 3, 4, 0, 0, 5, 6 ]\n\n","type":"List.List a -> List.List (List.List a) -> List.List a"},{"name":"interweave","comment":" Return a list that contains elements from the two provided, in alternate order.\nIf one list runs out of items, append the items from the remaining list.\n\n interweave [ 1, 3 ] [ 2, 4 ]\n --> [ 1, 2, 3, 4 ]\n\n interweave [ 1, 3, 5, 7 ] [ 2, 4 ]\n --> [ 1, 2, 3, 4, 5, 7 ]\n\n interweave [ 4, 9, 16 ] [ 2, 3, 5, 7 ]\n --> [ 4, 2, 9, 3, 16, 5, 7 ]\n\n","type":"List.List a -> List.List a -> List.List a"},{"name":"isInfixOf","comment":" Return True if all the elements of the first list occur in-order and\nconsecutively anywhere within the second.\n\n isInfixOf [ 5, 7, 11 ] [ 2, 3, 5, 7, 11, 13 ]\n --> True\n\n isInfixOf [ 5, 7, 13 ] [ 2, 3, 5, 7, 11, 13 ]\n --> False\n\n isInfixOf [ 3, 5, 2 ] [ 2, 3, 5, 7, 11, 13 ]\n --> False\n\n","type":"List.List a -> List.List a -> Basics.Bool"},{"name":"isPermutationOf","comment":" Take two lists and return `True`, if the first list is a permutation of the second list.\nIn other words: Do the 2 `List`s contain the same elements but in a different order?\n\n [ 3, 1, 2 ]\n |> isPermutationOf\n [ 1, 2, 3 ]\n --> True\n\n [ 3, 1, 0 ]\n |> isPermutationOf\n [ 1, 2, 3 ]\n --> False\n\n [ 3, 1, 2, 2 ]\n |> isPermutationOf\n [ 1, 2, 3 ]\n --> False\n\n","type":"List.List a -> List.List a -> Basics.Bool"},{"name":"isPrefixOf","comment":" Take two lists and return `True`, if the first list is the prefix of the second list.\n","type":"List.List a -> List.List a -> Basics.Bool"},{"name":"isSubsequenceOf","comment":" Return True if all the elements of the first list occur, in order, in the\nsecond. The elements do not have to occur consecutively.\n\n isSubsequenceOf\n [ \"E\", \"l\", \"m\" ]\n [ \"E\", \"a\", \"t\", \" \", \"l\", \"i\", \"m\", \"e\", \"s\" ]\n --> True\n\n isSubsequenceOf\n [ \"E\", \"l\", \"m\" ]\n [ \"E\", \"m\", \"a\", \"i\", \"l\" ]\n --> False\n\n","type":"List.List a -> List.List a -> Basics.Bool"},{"name":"isSuffixOf","comment":" Take two lists and return `True`, if the first list is the suffix of the second list.\n","type":"List.List a -> List.List a -> Basics.Bool"},{"name":"iterate","comment":" Returns a list of repeated applications of `f`. If `f` returns `Nothing`\nthe iteration will stop. If it returns `Just y` then `y` will be added to the\nlist and the iteration will continue with `f y`.\n\n collatz : Int -> Maybe Int\n collatz n =\n if n == 1 then\n Nothing\n else\n Just <|\n if modBy 2 n == 0 then\n n // 2\n else\n 3 * n + 1\n\n iterate collatz 13\n --> [13,40,20,10,5,16,8,4,2,1]\n\n","type":"(a -> Maybe.Maybe a) -> a -> List.List a"},{"name":"joinOn","comment":" Performs an inner join, combining data items from both lists if they match by their respective key functions.\n\n employees : List { name : String, departmentId : Int }\n employees =\n [ { name = \"Rafferty\", departmentId = 31 }\n , { name = \"Jones\", departmentId = 33 }\n , { name = \"Heisenberg\", departmentId = 33 }\n , { name = \"Robinson\", departmentId = 34 }\n , { name = \"Smith\", departmentId = 34 }\n ]\n\n departments : List { name : String, departmentId : Int }\n departments =\n [ { departmentId = 31, name = \"Sales\" }\n , { departmentId = 33, name = \"Engineering\" }\n , { departmentId = 34, name = \"Clerical\" }\n , { departmentId = 35, name = \"Marketing\" }\n ]\n\n joinOn (\\empl dep -> { employee = empl.name, department = dep.name}) .departmentId .departmentId employees departments\n --> [ { department = \"Clerical\", employee = \"Robinson\" }\n --> , { department = \"Clerical\", employee = \"Smith\" }\n --> , { department = \"Engineering\", employee = \"Jones\" }\n --> , { department = \"Engineering\", employee = \"Heisenberg\" }\n --> , { department = \"Sales\", employee = \"Rafferty\" }\n --> ]\n\nThis is akin to the SQL query:\n\n SELECT employee.name, department.name\n FROM employee\n INNER JOIN department\n ON employee.departmentId = department.departmentId\n\n","type":"(a -> b -> c) -> (a -> comparable) -> (b -> comparable) -> List.List a -> List.List b -> List.List c"},{"name":"last","comment":" Extract the last element of a list.\n\n last [ 1, 2, 3 ]\n --> Just 3\n\n last []\n --> Nothing\n\n","type":"List.List a -> Maybe.Maybe a"},{"name":"lift2","comment":" Map functions taking multiple arguments over multiple lists, regardless of list length.\nAll possible combinations will be explored.\n\n lift2 (+) [1,2,3][4,5]\n --> [5,6,6,7,7,8]\n\n","type":"(a -> b -> c) -> List.List a -> List.List b -> List.List c"},{"name":"lift3","comment":" ","type":"(a -> b -> c -> d) -> List.List a -> List.List b -> List.List c -> List.List d"},{"name":"lift4","comment":" ","type":"(a -> b -> c -> d -> e) -> List.List a -> List.List b -> List.List c -> List.List d -> List.List e"},{"name":"mapAccuml","comment":" The mapAccuml function behaves like a combination of map and foldl; it applies a\nfunction to each element of a list, passing an accumulating parameter from left to right,\nand returning a final value of this accumulator together with the new list.\n\n mapAccuml f a0 [ x1, x2, x3 ] == ( a3, [ y1, y2, y3 ] )\n\n -- x1 x2 x3\n -- | | |\n -- a0 -- f --- f --- f -> a3\n -- | | |\n -- y1 y2 y3\n\nAdd a running total to a list of numbers:\n\n mapAccuml (\\a x -> ( a + x, ( x, a + x ) )) 0 [ 2, 4, 8 ]\n --> ( 14, [ ( 2, 2 ), ( 4, 6 ), ( 8, 14 ) ] )\n\nMap number by multiplying with accumulated sum:\n\n mapAccuml (\\a x -> ( a + x, a * x )) 5 [ 2, 4, 8 ]\n --> ( 19, [ 10, 28, 88 ] )\n\n","type":"(a -> b -> ( a, c )) -> a -> List.List b -> ( a, List.List c )"},{"name":"mapAccumr","comment":" The mapAccumr function behaves like a combination of map and foldr; it applies a\nfunction to each element of a list, passing an accumulating parameter from right to left,\nand returning a final value of this accumulator together with the new list.\n\n mapAccumr f a0 [ x1, x2, x3 ] == ( a3, [ y1, y2, y3 ] )\n\n -- x1 x2 x3\n -- | | |\n -- a3 <- f --- f --- f -- a0\n -- | | |\n -- y1 y2 y3\n\nAdd a count of remaining elements:\n\n mapAccumr (\\a x -> ( a + 1, ( x, a ) )) 0 [ 2, 4, 8 ]\n --> ( 3, [ ( 2, 2 ), ( 4, 1 ), ( 8, 0 ) ] )\n\nMap number by multiplying with right-to-left accumulated sum:\n\n mapAccumr (\\a x -> ( a + x, a * x )) 5 [ 2, 4, 8 ]\n --> ( 19, [ 34, 52, 40 ] )\n\n","type":"(a -> b -> ( a, c )) -> a -> List.List b -> ( a, List.List c )"},{"name":"maximumBy","comment":" Find the first maximum element in a list using a comparable transformation\n","type":"(a -> comparable) -> List.List a -> Maybe.Maybe a"},{"name":"maximumWith","comment":" Find the first maximum element in a list using a comparison function\n\n maximumWith compare []\n --> Nothing\n\n maximumWith\n (\\x y -> compare x.val y.val)\n [{id=1, val=1}, {id=2, val=2}, {id=3,val=2}]\n --> Just { id = 2, val = 2 }\n\n","type":"(a -> a -> Basics.Order) -> List.List a -> Maybe.Maybe a"},{"name":"minimumBy","comment":" Find the first minimum element in a list using a comparable transformation\n","type":"(a -> comparable) -> List.List a -> Maybe.Maybe a"},{"name":"minimumWith","comment":" Find the first minimum element in a list using a comparison function\n\n minimumWith compare []\n --> Nothing\n minimumWith\n (\\x y -> compare x.val y.val)\n [{id=1, val=2}, {id=2, val=1}, {id=3,val=1}]\n --> Just { id = 2, val = 1 }\n\n","type":"(a -> a -> Basics.Order) -> List.List a -> Maybe.Maybe a"},{"name":"notMember","comment":" Negation of `member`.\n\n notMember 1 [ 1, 2, 3 ]\n --> False\n\n notMember 4 [ 1, 2, 3 ]\n --> True\n\n","type":"a -> List.List a -> Basics.Bool"},{"name":"permutations","comment":" Return the list of of all permutations of a list. The result is in lexicographic order.\n\n permutations [ 1, 2, 3 ]\n --> [ [ 1, 2, 3 ], [ 1, 3, 2 ], [ 2, 1, 3 ], [ 2, 3, 1 ], [ 3, 1, 2 ], [ 3, 2, 1 ] ]\n\n","type":"List.List a -> List.List (List.List a)"},{"name":"remove","comment":" Remove the first occurrence of a value from a list.\n","type":"a -> List.List a -> List.List a"},{"name":"removeAt","comment":" Remove the element at an index from a list. Return the original list if the index is out of range.\n\n removeAt 0 [ 1, 2, 3 ]\n --> [ 2, 3 ]\n\nSee also `removeIfIndex`.\n\n","type":"Basics.Int -> List.List a -> List.List a"},{"name":"removeIfIndex","comment":" Remove an element at an index that satisfies a predicate.\n\n removeIfIndex ((==) 2) [ 1, 2, 3 ]\n --> [ 1, 2 ]\n\nSee also `removeAt`.\n\n","type":"(Basics.Int -> Basics.Bool) -> List.List a -> List.List a"},{"name":"reverseFilter","comment":" `reverseMap f xs` gives the same result as `List.reverse (List.map f xs)`,\nbut is tail-recursive and slightly more efficient.\n\n reverseFilter (\\x -> x > 5) [ 1, 4, 9, 16]\n --> [ 16, 9 ]\n\n","type":"(a -> Basics.Bool) -> List.List a -> List.List a"},{"name":"reverseMap","comment":" `reverseMap f xs` gives the same result as `List.reverse (List.map f xs)`,\nbut is tail-recursive and slightly more efficient.\n\n reverseMap sqrt [ 1, 4, 9 ]\n --> [ 3, 2, 1 ]\n\n","type":"(a -> b) -> List.List a -> List.List b"},{"name":"reverseRange","comment":" Create a list of numbers, every element decreasing by one.\nYou give the highest and lowest number that should be in the list.\nMore efficient than calling `List.reverse (List.range lo hi)`\n\n range 6 3 == [ 6, 5, 4, 3 ]\n\n range 3 3 == [ 3 ]\n\n range 3 6 == []\n\n","type":"Basics.Int -> Basics.Int -> List.List Basics.Int"},{"name":"scanl","comment":" Reduce a list from the left, building up all of the intermediate results into a list.\n\n scanl (+) 0 [ 1, 2, 3, 4 ]\n --> [ 0, 1, 3, 6, 10 ]\n\n","type":"(a -> b -> b) -> b -> List.List a -> List.List b"},{"name":"scanl1","comment":" `scanl1` is a variant of `scanl` that has no starting value argument.\n\nCompare:\n\n scanl (+) 0 [ 1, 2, 3 ]\n --> [ 0, 1, 3, 6 ]\n\n scanl1 (+) [ 1, 2, 3 ]\n --> [ 1, 3, 6 ]\n\n scanl (-) 0 [ 1, 2, 3 ]\n --> [ 0, 1, 1, 2 ]\n\n scanl1 (-) [ 1, 2, 3 ]\n --> [ 1, 1, 2 ]\n\n","type":"(a -> a -> a) -> List.List a -> List.List a"},{"name":"scanr","comment":" `scanr` is a right-to-left dual of `scanl`. Note that:\n\n head (scanr f z xs) == foldr f z xs\n\nExamples:\n\n scanr (+) 0 [ 1, 2, 3 ]\n --> [ 6, 5, 3, 0 ]\n\n scanr (-) 0 [ 1, 2, 3 ]\n --> [ 2, -1, 3, 0 ]\n\n","type":"(a -> b -> b) -> b -> List.List a -> List.List b"},{"name":"scanr1","comment":" `scanr1` is a variant of `scanr` that has no starting value argument.\n\n scanr1 (+) [ 1, 2, 3 ]\n --> [ 6, 5, 3 ]\n\n scanr1 (-) [ 1, 2, 3 ]\n --> [ 2, -1, 3 ]\n\n","type":"(a -> a -> a) -> List.List a -> List.List a"},{"name":"select","comment":" Return all combinations in the form of (element, rest of the list). Read [Haskell Libraries proposal](https://mail.haskell.org/pipermail/libraries/2008-February/009270.html) for further ideas on how to use this function.\n\n select [ 1, 2, 3, 4 ]\n --> [ ( 1, [ 2, 3, 4 ] ), ( 2, [ 1, 3, 4 ] ), ( 3, [ 1, 2, 4 ] ), ( 4, [ 1, 2, 3 ] ) ]\n\n","type":"List.List a -> List.List ( a, List.List a )"},{"name":"selectSplit","comment":" Return all combinations in the form of (elements before, element, elements after).\n\n selectSplit [ 1, 2, 3 ]\n --> [ ( [], 1, [ 2, 3 ] ), ( [ 1 ], 2, [ 3 ] ), ( [ 1, 2 ], 3, [] ) ]\n\n","type":"List.List a -> List.List ( List.List a, a, List.List a )"},{"name":"setAt","comment":" Set a value in a list by index. Return the original list if the index is out of range.\n\n setAt 0 42 [ 1, 2, 3 ]\n --> [ 42, 2, 3 ]\n\n","type":"Basics.Int -> a -> List.List a -> List.List a"},{"name":"setIf","comment":" Replace all values that satisfy a predicate with a replacement value.\n","type":"(a -> Basics.Bool) -> a -> List.List a -> List.List a"},{"name":"span","comment":" Take a predicate and a list, return a tuple. The first part of the tuple is the longest prefix of that list, for each element of which the predicate holds. The second part of the tuple is the remainder of the list. `span p xs` is equivalent to `(takeWhile p xs, dropWhile p xs)`.\n\n span ((>) 3) [ 1, 2, 3, 4, 1, 2, 3, 4 ]\n --> ( [ 1, 2 ], [ 3, 4, 1, 2, 3, 4 ] )\n\n span ((>) 5) [ 1, 2, 3 ]\n --> ( [ 1, 2, 3 ], [] )\n\n span ((>) 0) [ 1, 2, 3 ]\n --> ( [], [ 1, 2, 3 ] )\n\n","type":"(a -> Basics.Bool) -> List.List a -> ( List.List a, List.List a )"},{"name":"splitAt","comment":" Take a number and a list, return a tuple of lists, where first part is prefix of the list of length equal the number, and second part is the remainder of the list. `splitAt n xs` is equivalent to `(take n xs, drop n xs)`.\n\n splitAt 3 [ 1, 2, 3, 4, 5 ]\n --> ( [ 1, 2, 3 ], [ 4, 5 ] )\n\n splitAt 1 [ 1, 2, 3 ]\n --> ( [ 1 ], [ 2, 3 ] )\n\n splitAt 3 [ 1, 2, 3 ]\n --> ( [ 1, 2, 3 ], [] )\n\n splitAt 4 [ 1, 2, 3 ]\n --> ( [ 1, 2, 3 ], [] )\n\n splitAt 0 [ 1, 2, 3 ]\n --> ( [], [ 1, 2, 3 ] )\n\n splitAt -1 [ 1, 2, 3 ]\n --> ( [], [ 1, 2, 3 ] )\n\n","type":"Basics.Int -> List.List a -> ( List.List a, List.List a )"},{"name":"splitWhen","comment":" Attempts to split the list at the first element where the given predicate is true. If the predicate is not true for any elements in the list, return nothing. Otherwise, return the split list.\n\n splitWhen (\\n -> n == 3) [ 1, 2, 3, 4, 5 ]\n --> Just ( [ 1, 2 ], [ 3, 4, 5 ] )\n\n splitWhen (\\n -> n == 6) [ 1, 2, 3, 4, 5 ]\n --> Nothing\n\n","type":"(a -> Basics.Bool) -> List.List a -> Maybe.Maybe ( List.List a, List.List a )"},{"name":"stableSortWith","comment":" Similar to List.sortWith, this sorts values with a custom comparison function.\nUnlike List.sortWith, this sort is guaranteed to be a stable sort.\nNote that List.sortWith is faster and is preferred if sort stability is not required.\n","type":"(a -> a -> Basics.Order) -> List.List a -> List.List a"},{"name":"stoppableFoldl","comment":" A `foldl` that can stop early instead of traversing the whole list.\n\n stoppableFoldl\n (\\n acc ->\n if acc >= 50 then\n Stop acc\n else\n Continue (n + acc)\n )\n 0\n (List.range 1 10000)\n --> 55\n\n","type":"(a -> b -> List.Extra.Step b) -> b -> List.List a -> b"},{"name":"stripPrefix","comment":" Drop the given prefix from the list. If the list doesn't start with that prefix, return `Nothing`.\n\n stripPrefix [ 1, 2 ] [ 1, 2, 3, 4 ]\n --> Just [ 3, 4 ]\n\n stripPrefix [ 1, 2, 3 ] [ 1, 2, 3, 4, 5 ]\n --> Just [ 4, 5 ]\n\n stripPrefix [ 1, 2, 3 ] [ 1, 2, 3 ]\n --> Just []\n\n stripPrefix [ 1, 2, 3 ] [ 1, 2 ]\n --> Nothing\n\n stripPrefix [ 3, 2, 1 ] [ 1, 2, 3, 4, 5 ]\n --> Nothing\n\n","type":"List.List a -> List.List a -> Maybe.Maybe (List.List a)"},{"name":"subsequences","comment":" Return the list of all subsequences of a list.\n\n subsequences [ 1, 2, 3 ]\n --> [ [], [ 1 ], [ 2 ], [ 1, 2 ], [ 3 ], [ 1, 3 ], [ 2, 3 ], [ 1, 2, 3 ] ]\n\n","type":"List.List a -> List.List (List.List a)"},{"name":"subsequencesNonEmpty","comment":" Return the list of all subsequences of the argument, except for the empty list.\n\n subsequencesNonEmpty [ 1, 2, 3 ]\n == [ [ 1 ], [ 2 ], [ 1, 2 ], [ 3 ], [ 1, 3 ], [ 2, 3 ], [ 1, 2, 3 ] ]\n\n","type":"List.List a -> List.List ( a, List.List a )"},{"name":"swapAt","comment":" Swap two values in a list by index. Return the original list if the index is out of range.\nIf the same index is supplied twice the operation has no effect.\n\n swapAt 1 2 [ 1, 2, 3 ]\n --> [ 1, 3, 2 ]\n\n","type":"Basics.Int -> Basics.Int -> List.List a -> List.List a"},{"name":"tails","comment":" Return all final segments of a list, from longest to shortest, the list itself first, empty list last.\n\n tails [ 1, 2, 3 ]\n --> [ [ 1, 2, 3 ], [ 2, 3 ], [ 3 ], [] ]\n\n","type":"List.List a -> List.List (List.List a)"},{"name":"takeWhile","comment":" Take elements in order as long as the predicate evaluates to `True`\n","type":"(a -> Basics.Bool) -> List.List a -> List.List a"},{"name":"takeWhileRight","comment":" Take elements from the right, while predicate still holds.\n\n takeWhileRight ((<) 5) (List.range 1 10)\n --> [ 6, 7, 8, 9, 10 ]\n\n","type":"(a -> Basics.Bool) -> List.List a -> List.List a"},{"name":"transpose","comment":" Transpose rows and columns of the list of lists.\n\n transpose [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]\n --> [ [ 1, 4 ], [ 2, 5 ], [ 3, 6 ] ]\n\n transpose [ [ 10, 11 ], [ 20, 40 ], [ 30, 31, 32, 400 ] ]\n --> [ [ 10, 20, 30 ], [ 11, 40, 31 ] ]\n\n","type":"List.List (List.List a) -> List.List (List.List a)"},{"name":"uncons","comment":" Decompose a list into its head and tail. If the list is empty, return `Nothing`. Otherwise, return `Just (x, xs)`, where `x` is head and `xs` is tail.\n\n uncons [1,2,3]\n --> Just (1, [2,3])\n\n uncons []\n --> Nothing\n\n","type":"List.List a -> Maybe.Maybe ( a, List.List a )"},{"name":"unconsLast","comment":" Decompose a list into its body and last element. If the list is empty, return `Nothing`. Otherwise, return `Just (x, xs)`, where `x` is the last element and `xs` is the body.\n\n unconsLast [1,2,3]\n --> Just (3, [1,2])\n\n unconsLast []\n --> Nothing\n\n","type":"List.List a -> Maybe.Maybe ( a, List.List a )"},{"name":"unfoldr","comment":" The `unfoldr` function is \"dual\" to `foldr`. `foldr` reduces a list to a summary value, `unfoldr` builds a list from a seed. The function takes a function and a starting element. It applies the function to the element. If the result is `Just (a, b)`, `a` is accumulated and the function is applied to `b`. If the result is `Nothing`, the list accumulated so far is returned.\n\n subtractOneUntilZero : Int -> Maybe (Int, Int)\n subtractOneUntilZero i =\n if i /= 0 then\n Just (i, i - 1)\n else\n Nothing\n\n unfoldr subtractOneUntilZero 5\n --> [ 5, 4, 3, 2, 1 ]\n\n","type":"(b -> Maybe.Maybe ( a, b )) -> b -> List.List a"},{"name":"unique","comment":" Remove duplicate values, keeping the first instance of each element which appears more than once.\n\n unique [ 0, 1, 1, 0, 1 ]\n --> [ 0, 1 ]\n\n","type":"List.List a -> List.List a"},{"name":"uniqueBy","comment":" Drop duplicates where what is considered to be a duplicate is the result of first applying the supplied function to the elements of the list.\n","type":"(a -> b) -> List.List a -> List.List a"},{"name":"uniquePairs","comment":" Return all ways to pair the elements of the list.\n(Essentially, enumerate the possible \"handshakes.\")\n\nThe order of the pair elements doesn't matter, so if `(1,2)` is a returned pair,\nwe don't return `(2,1)`.\n\nIn more mathematical terms these are 2-combinations without repetition.\n\n uniquePairs [ 1, 2, 3, 4 ]\n --> [ ( 1, 2 ), ( 1, 3 ), ( 1, 4 ), ( 2, 3 ), ( 2, 4 ), ( 3, 4 ) ]\n\nIn this example, everybody shakes hands with three other people.\n\n","type":"List.List a -> List.List ( a, a )"},{"name":"updateAt","comment":" Replace a value at a specific index by calling an update function. Return the original list if the index is out of range.\n\n updateAt 0 ((+) 1) [ 1, 2, 3 ]\n --> [ 2, 2, 3 ]\n\nSee also `updateIfIndex`.\n\n","type":"Basics.Int -> (a -> a) -> List.List a -> List.List a"},{"name":"updateIf","comment":" Replace all values that satisfy a predicate by calling an update function.\n","type":"(a -> Basics.Bool) -> (a -> a) -> List.List a -> List.List a"},{"name":"updateIfIndex","comment":" Replace a value at an index that satisfies a predicate, by calling an update function.\n\n updateIfIndex ((==) 2) ((+) 1) [ 1, 2, 3 ]\n --> [ 1, 2, 4 ]\n\nSee also `updateAt`.\n\n","type":"(Basics.Int -> Basics.Bool) -> (a -> a) -> List.List a -> List.List a"},{"name":"zip","comment":" Take two lists and returns a list of corresponding pairs\n","type":"List.List a -> List.List b -> List.List ( a, b )"},{"name":"zip3","comment":" Take three lists and returns a list of triples\n","type":"List.List a -> List.List b -> List.List c -> List.List ( a, b, c )"}],"binops":[]},{"name":"Maybe.Extra","comment":" Convenience functions for [`Maybe`](https://package.elm-lang.org/packages/elm/core/latest/Maybe).\n\n\n# Basics\n\nWork with 1 `Maybe`\n\n@docs isJust, isNothing, join, filter\n\n\n# Get a value out of a `Maybe`\n\n@docs withDefaultLazy, unwrap, unpack\n\n\n# Or\n\nTake the first value that's present\n\n@docs or, orElse, orList, orLazy, orElseLazy, orListLazy, oneOf\n\n\n# Lists of `Maybe`s\n\n@docs values\n@docs combine, traverse, combineArray, traverseArray\n\n\n# toList\n\n@docs toList, toArray\n@docs cons\n\n\n# andThenN\n\nThese functions are just like [`andThen`](https://package.elm-lang.org/packages/elm/core/latest/Maybe#andThen), except they take multiple arguments.\n\nAll arguments must be `Just` and the function must return a `Just` for the result to be `Just`.\n\nIf you need a version of `andThenN` that takes more than 4 arguments, you can chain together [`andMap`](#andMap) calls in a pipeline.\n\n@docs andThen2, andThen3, andThen4\n\n\n# Applicative Functions\n\n@docs andMap, next, prev\n\n","unions":[],"aliases":[],"values":[{"name":"andMap","comment":" If both a function and a value are present, apply the function to the value.\nIf either argument is `Nothing`, return `Nothing`.\n\n Just ((+) 2)\n |> andMap (Just 3)\n --> Just 5\n\n Nothing\n |> andMap (Just 3)\n --> Nothing\n\n Just ((+) 2)\n |> andMap Nothing\n --> Nothing\n\nThis can be used to do [`Maybe.mapN`](https://package.elm-lang.org/packages/elm/core/latest/Maybe#map2) or [`andThenN`](#andThenN) for any number of arguments.\n\n -- map4\n Just (\\a b c d -> a + b + c + d )\n |> andMap (Just 1)\n |> andMap (Just 2)\n |> andMap (Just 4)\n |> andMap (Just 8)\n --> Just 15\n\n -- andThen4\n Just (\\a b c d -> Just (a + b + c + d ))\n |> andMap (Just 1)\n |> andMap (Just 2)\n |> andMap (Just 4)\n |> andMap (Just 8)\n |> join\n --> Just 15\n\nAdvanced functional programmers will recognize this as the implementation of `<*>` for `Maybe`s from the `Applicative` typeclass.\n\n","type":"Maybe.Maybe a -> Maybe.Maybe (a -> b) -> Maybe.Maybe b"},{"name":"andThen2","comment":"\n\n import Array exposing (Array)\n\n array : Array Int\n array = Array.fromList [1,2,3]\n\n andThen2 Array.get (Just 1) (Just array)\n --> Just 2\n\n andThen2 Array.get Nothing (Just array)\n --> Nothing\n\n andThen2 Array.get (Just 1) Nothing\n --> Nothing\n\n andThen2 Array.get (Just 4) (Just array)\n --> Nothing\n\n","type":"(a -> b -> Maybe.Maybe value) -> Maybe.Maybe a -> Maybe.Maybe b -> Maybe.Maybe value"},{"name":"andThen3","comment":" ","type":"(a -> b -> c -> Maybe.Maybe value) -> Maybe.Maybe a -> Maybe.Maybe b -> Maybe.Maybe c -> Maybe.Maybe value"},{"name":"andThen4","comment":" ","type":"(a -> b -> c -> d -> Maybe.Maybe value) -> Maybe.Maybe a -> Maybe.Maybe b -> Maybe.Maybe c -> Maybe.Maybe d -> Maybe.Maybe value"},{"name":"combine","comment":" If every `Maybe` in the list is present, return all of the values unwrapped.\nIf there are any `Nothing`s, the whole function fails and returns `Nothing`.\n\n combine []\n --> Just []\n\n combine [ Just 1, Just 2, Just 3 ]\n --> Just [ 1, 2, 3 ]\n\n combine [ Just 1, Nothing, Just 3 ]\n --> Nothing\n\n","type":"List.List (Maybe.Maybe a) -> Maybe.Maybe (List.List a)"},{"name":"combineArray","comment":" Like [`combine`](#combine),\nbut works on [`Array`](https://package.elm-lang.org/packages/elm/core/latest/Array) instead of `List`.\n","type":"Array.Array (Maybe.Maybe a) -> Maybe.Maybe (Array.Array a)"},{"name":"cons","comment":" Add an item to a list only if it's a `Just`.\n\n cons (Just 1) [ 2, 3 ]\n --> [ 1, 2, 3 ]\n\n cons Nothing [2, 3 ]\n --> [ 2, 3 ]\n\n","type":"Maybe.Maybe a -> List.List a -> List.List a"},{"name":"filter","comment":" Keep the `Maybe` only if the predicate function passes\n\n filter (\\v -> v == 1) (Just 1)\n --> Just 1\n\n filter (\\v -> v == 2) (Just 1)\n --> Nothing\n\n filter (\\v -> v == 1) Nothing\n --> Nothing\n\n","type":"(a -> Basics.Bool) -> Maybe.Maybe a -> Maybe.Maybe a"},{"name":"isJust","comment":"\n\n isJust (Just 42)\n --> True\n\n isJust (Just [])\n --> True\n\n isJust Nothing\n --> False\n\n","type":"Maybe.Maybe a -> Basics.Bool"},{"name":"isNothing","comment":"\n\n isNothing (Just 42)\n --> False\n\n isNothing (Just [])\n --> False\n\n isNothing Nothing\n --> True\n\n","type":"Maybe.Maybe a -> Basics.Bool"},{"name":"join","comment":" Flattens nested `Maybe`s\n\n join (Just (Just 1))\n --> Just 1\n\n join (Just Nothing)\n --> Nothing\n\n join Nothing\n --> Nothing\n\n","type":"Maybe.Maybe (Maybe.Maybe a) -> Maybe.Maybe a"},{"name":"next","comment":" Take two `Maybe` values. If the first one equals `Nothing`, return `Nothing`. Otherwise return the second value.\n\n next (Just 1) (Just 2)\n --> Just 2\n\n next Nothing (Just 2)\n --> Nothing\n\n next (Just 1) Nothing\n --> Nothing\n\nAdvanced functional programmers will recognize this as the implementation of `*>` for `Maybe`s from the `Applicative` typeclass.\n\n","type":"Maybe.Maybe a -> Maybe.Maybe b -> Maybe.Maybe b"},{"name":"oneOf","comment":" Try a list of functions against a value. Return the value of the first call that succeeds (returns `Just`).\n\n type UserInput\n = FloatInput Float\n | IntInput Int\n | UnknownInput\n\n \"5.6\"\n |> oneOf\n [ String.toInt >> Maybe.map IntInput\n , String.toFloat >> Maybe.map FloatInput\n ]\n |> Maybe.withDefault UnknownInput\n --> FloatInput 5.6\n\n","type":"List.List (a -> Maybe.Maybe b) -> a -> Maybe.Maybe b"},{"name":"or","comment":" Returns the first value that is present, like the boolean `||`.\n\nBoth values will be computed. There is no short-circuiting.\nIf your second argument is expensive to calculate and you need short circuiting, use [`orLazy`](#orLazy) instead.\n\n or (Just 4) (Just 5)\n --> Just 4\n\n or (Just 4) Nothing\n --> Just 4\n\n or Nothing (Just 5)\n --> Just 5\n\n or Nothing Nothing\n --> Nothing\n\nAdvanced functional programmers will recognize this as the\nimplementation of `mplus` for `Maybe`s from the `MonadPlus` type\nclass.\n\n","type":"Maybe.Maybe a -> Maybe.Maybe a -> Maybe.Maybe a"},{"name":"orElse","comment":" Piping-friendly version of [`or`](#or).\n\n Just 5\n |> orElse (Just 4)\n --> Just 5\n\n orElse (Just 4) (Just 5)\n --> Just 5\n\n List.head []\n |> orElse (List.head [ 4 ])\n --> Just 4\n\n","type":"Maybe.Maybe a -> Maybe.Maybe a -> Maybe.Maybe a"},{"name":"orElseLazy","comment":" Lazy version of [`orElse`](#orElse).\nPiping-friendly version of [`orLazy`](#orLazy).\n\nThe first argument will only be evaluated if the second argument is `Nothing`.\n\n Just 4\n |> orElseLazy (\\() -> Debug.todo \"Expensive calculation\")\n --> Just 4\n\n","type":"(() -> Maybe.Maybe a) -> Maybe.Maybe a -> Maybe.Maybe a"},{"name":"orLazy","comment":" Lazy version of [`or`](#or).\n\nThe second argument will only be evaluated if the first argument is `Nothing`.\n\n orLazy (Just 4) (\\() -> Debug.todo \"Expensive calculation\")\n --> Just 4\n\n","type":"Maybe.Maybe a -> (() -> Maybe.Maybe a) -> Maybe.Maybe a"},{"name":"orList","comment":" Returns the first value that is present.\n\nAll values will be computed.\nIf your arguments are expensive to calculate, use [`orListLazy`](#orListLazy) instead.\n\n orList\n [ Nothing\n , Just 1\n , Just 2\n ]\n --> Just 1\n\n orList\n [ List.head []\n , String.toInt \"\"\n ]\n --> Nothing\n\n orList []\n --> Nothing\n\n","type":"List.List (Maybe.Maybe a) -> Maybe.Maybe a"},{"name":"orListLazy","comment":" Lazy version of [`orList`](#orList)\n\nStops calculating new values after the first match\n\n orListLazy\n [ \\() -> Nothing\n , \\() -> Just 1\n , \\() -> Debug.todo \"Expensive calculation\"\n ]\n --> Just 1\n\n","type":"List.List (() -> Maybe.Maybe a) -> Maybe.Maybe a"},{"name":"prev","comment":" Take two `Maybe` values. If the second one equals `Nothing`, return `Nothing`. Otherwise return the first value.\n\n prev (Just 1) (Just 2)\n --> Just 1\n\n prev Nothing (Just 2)\n --> Nothing\n\n prev (Just 1) Nothing\n --> Nothing\n\nAdvanced functional programmers will recognize this as the implementation of `<*` for `Maybe`s from the `Applicative` typeclass.\n\n","type":"Maybe.Maybe a -> Maybe.Maybe b -> Maybe.Maybe a"},{"name":"toArray","comment":" Like `toList`, but returns a singleton or empty [`Array`](https://package.elm-lang.org/packages/elm/core/latest/Array).\n\n import Array\n\n toArray Nothing\n --> Array.fromList []\n\n toArray (Just 1)\n --> Array.fromList [ 1 ]\n\n","type":"Maybe.Maybe a -> Array.Array a"},{"name":"toList","comment":" A `Maybe` is a lot like a list that can only be length 0 or 1.\n\nReturns a singleton list if the value is present, and an empty list it's missing.\n\n toList Nothing\n --> []\n\n toList (Just 1)\n --> [ 1 ]\n\n","type":"Maybe.Maybe a -> List.List a"},{"name":"traverse","comment":" Like [`combine`](#combine), but map a function over each element of the list first.\n\nIf every function call succeeds (returns `Just`), `traverse` will return a list.\nIf any function call fails (returns `Nothing`), `traverse` will return `Nothing`.\n\n`combine` is equivalent to `traverse identity`.\n\n traverse (\\x -> Just (x * 10)) [ 1, 2, 3, 4, 5 ]\n --> Just [ 10, 20, 30, 40, 50 ]\n\n traverse List.head [ [1], [2, 3], [] ]\n --> Nothing\n\n","type":"(a -> Maybe.Maybe b) -> List.List a -> Maybe.Maybe (List.List b)"},{"name":"traverseArray","comment":" Like [`traverse`](#traverse),\nbut works on [`Array`](https://package.elm-lang.org/packages/elm/core/latest/Array) instead of `List`.\n","type":"(a -> Maybe.Maybe b) -> Array.Array a -> Maybe.Maybe (Array.Array b)"},{"name":"unpack","comment":" Like [`unwrap`](#unwrap), but the default value is lazy,\nand will only be computed if the `Maybe` is `Nothing`.\n\n unpack (\\() -> 0) String.length Nothing\n --> 0\n\n unpack (\\() -> 0) String.length (Just \"abc\")\n --> 3\n\n`unpack (\\() -> default) f maybeX` is equivalent to\n\n case maybeX of\n Just x ->\n f x\n\n Nothing ->\n default\n\n","type":"(() -> b) -> (a -> b) -> Maybe.Maybe a -> b"},{"name":"unwrap","comment":" Like using a `case`.\nGive a function that says what to do if the input is `Just`,\nand a value to use if the input is `Nothing`.\n\nThese are all equivalent:\n\n unwrap default f maybeX\n\n maybeX\n |> Maybe.map f\n |> Maybe.withDefault default\n\n case maybeX of\n Just x ->\n f x\n\n Nothing ->\n default\n\nExcept that unlike a `case`, the default value for `unwrap` is always computed.\nIf your default value is expensive to compute, use the lazy [`unpack`](#unpack) instead.\n\nExamples:\n\n unwrap 0 String.length Nothing\n --> 0\n\n unwrap 0 String.length (Just \"abc\")\n --> 3\n\n","type":"b -> (a -> b) -> Maybe.Maybe a -> b"},{"name":"values","comment":" Take all the values that are present, throwing away any `Nothing`s.\n\nEquivalent to [`List.filterMap identity`](https://package.elm-lang.org/packages/elm/core/latest/List#filterMap).\n\n values [ Just 1, Nothing, Just 2 ]\n --> [ 1, 2 ]\n\n","type":"List.List (Maybe.Maybe a) -> List.List a"},{"name":"withDefaultLazy","comment":" Lazy version of [Maybe.withDefault](https://package.elm-lang.org/packages/elm/core/latest/Maybe#withDefault).\n\nIt will only calculate the default if needed.\n\nExamples:\n\n withDefaultLazy (\\() -> 2 + 2) Nothing\n --> 4\n\n withDefaultLazy (\\() -> Debug.todo \"Expensive calculation\") (Just 4)\n --> 4\n\n","type":"(() -> a) -> Maybe.Maybe a -> a"}],"binops":[]},{"name":"Result.Extra","comment":" Convenience functions for working with `Result`.\n\n\n# Common Helpers\n\n@docs isOk, isErr, extract, unwrap, unpack, error, mapBoth, merge, join, partition, filter\n\n\n# Combining\n\n@docs combine, combineMap, combineFirst, combineSecond, combineBoth, combineMapFirst, combineMapSecond, combineMapBoth\n\n\n# Applying\n\n@docs singleton, andMap\n\n\n# Alternatives\n\n@docs or, orLazy, orElseLazy, orElse\n\n\n# Conversions\n\n@docs toTask\n\n","unions":[],"aliases":[],"values":[{"name":"andMap","comment":" Apply the function that is inside `Result` to a value that is inside\n`Result`. Return the result inside `Result`. If one of the `Result`\narguments is `Err e`, return `Err e`. Also known as `apply`.\n\n Err \"Oh\" |> andMap (Err \"No!\") == Err \"Oh\"\n\n Err \"Oh\" |> andMap (Ok 2) == Err \"Oh\"\n\n Ok ((+) 1) |> andMap (Err \"No!\") == Err \"No!\"\n\n Ok ((+) 1) |> andMap (Ok 2) == Ok 3\n\n","type":"Result.Result e a -> Result.Result e (a -> b) -> Result.Result e b"},{"name":"combine","comment":" Combine a list of results into a single result (holding a list).\nAlso known as `sequence` on lists.\n","type":"List.List (Result.Result x a) -> Result.Result x (List.List a)"},{"name":"combineBoth","comment":" Combine all results in a tuple\ninto a single result holding the tuple's values.\nAlso know as `bisequence` on tuples.\n","type":"( Result.Result x a, Result.Result x b ) -> Result.Result x ( a, b )"},{"name":"combineFirst","comment":" Pull a result out of the _first_ element of a tuple\nand combine it into a result holding the tuple's values.\n","type":"( Result.Result x a, c ) -> Result.Result x ( a, c )"},{"name":"combineMap","comment":" Map a function producing results on a list\nand combine those into a single result (holding a list).\nAlso known as `traverse` on lists.\n\n combineMap f xs == combine (List.map f xs)\n\n","type":"(a -> Result.Result x b) -> List.List a -> Result.Result x (List.List b)"},{"name":"combineMapBoth","comment":" Map a function producing results on the _both_ elements of a tuple\nand then pull them out using `combineBoth`.\nAlso know as `bitraverse` on tuples.\n\n combineMapBoth f g ( x, y )\n == combineBoth (Tuple.mapBoth f g ( x, y ))\n == Result.map2 Tuple.pair (f x) (g y)\n\n","type":"(a -> Result.Result x c) -> (b -> Result.Result x d) -> ( a, b ) -> Result.Result x ( c, d )"},{"name":"combineMapFirst","comment":" Map a function producing results on the _first_ element of a tuple\nand then pull it out using `combineFirst`.\nAlso know as `sequence` on tuples.\n\n combineMapFirst f ( x, y )\n == combineFirst (Tuple.mapFirst f ( x, y ))\n == Result.map (\\newX -> ( newX, y )) (f x)\n\n","type":"(a -> Result.Result x b) -> ( a, c ) -> Result.Result x ( b, c )"},{"name":"combineMapSecond","comment":" Map a function producing results on the _second_ element of a tuple\nand then pull it out using `combineSecond`.\nAlso know as `traverse` on tuples.\n\n combineMapSecond f ( x, y )\n == combineSecond (Tuple.mapSecond f ( x, y ))\n == Result.map (Tuple.pair x) (f y)\n\n","type":"(a -> Result.Result x b) -> ( c, a ) -> Result.Result x ( c, b )"},{"name":"combineSecond","comment":" Pull a result out of the _second_ element of a tuple\nand combine it into a result holding the tuple's values.\nAlso known as `sequence` on tuples.\n","type":"( c, Result.Result x a ) -> Result.Result x ( c, a )"},{"name":"error","comment":" Convert to a Maybe containing the error, if there is one.\n\n parseInt : String -> Result ParseError Int\n\n maybeParseError : String -> Maybe ParseError\n maybeParseError string =\n error (parseInt string)\n\n","type":"Result.Result e a -> Maybe.Maybe e"},{"name":"extract","comment":" Turn a `Result e a` to an `a`, by applying the conversion\nfunction specified to the `e`.\n","type":"(e -> a) -> Result.Result e a -> a"},{"name":"filter","comment":" Take a `Result` and a predicate function and return a `Result` with the\noriginal value when a predicate matches.\n\n filter \"is not 1\" (\\v -> v == 1) (Ok 1) == Ok 1\n\n filter \"is not 2\" (\\v -> v == 2) (Ok 1) == Err \"is not 2\"\n\n","type":"e -> (a -> Basics.Bool) -> Result.Result e a -> Result.Result e a"},{"name":"isErr","comment":" Check whether the result is `Err` without unwrapping it.\n","type":"Result.Result e a -> Basics.Bool"},{"name":"isOk","comment":" Check whether the result is `Ok` without unwrapping it.\n","type":"Result.Result e a -> Basics.Bool"},{"name":"join","comment":" Join contained results with the same error into one result.\n\nUsefull if you have a \"result in a result\":\n\n join <| Ok (Ok 4) == Ok 4\n\n join <| Ok (Err \"message\") == Err \"message\"\n\n","type":"Result.Result x (Result.Result x a) -> Result.Result x a"},{"name":"mapBoth","comment":" Apply the first argument function to an `Err` and the second\nargument function to an `Ok` of a `Result`.\n","type":"(e -> f) -> (a -> b) -> Result.Result e a -> Result.Result f b"},{"name":"merge","comment":" Eliminate Result when error and success have been mapped to the same\ntype, such as a message type.\n\n merge (Ok 4) == 4\n\n merge (Err -1) == -1\n\nMore pragmatically:\n\n type Msg\n = UserTypedInt Int\n | UserInputError String\n\n msgFromInput : String -> Msg\n msgFromInput =\n String.toInt\n >> Result.mapError UserInputError\n >> Result.map UserTypedInt\n >> Result.Extra.merge\n\n","type":"Result.Result a a -> a"},{"name":"or","comment":" Like the Boolean `||` this will return the first value that is\npositive (`Ok`). However, unlike with `||`, both values will be\ncomputed anyway (there is no short-circuiting).\n\n or (Ok 4) (Ok 5) == Ok 4\n\n or (Err \"Oh!\") (Ok 5) == Ok 5\n\n or (Ok 4) (Err \"No!\") == Ok 4\n\n or (Err \"Oh!\") (Err \"No!\") == Err \"No!\"\n\nAs the last example line shows, the second error is returned if both\nresults are erroneous.\n\n","type":"Result.Result e a -> Result.Result e a -> Result.Result e a"},{"name":"orElse","comment":" Strict version of `orElseLazy` (and at the same time,\npiping-friendly version of `or`).\n\n orElse (Ok 4) (Ok 5) == Ok 5 -- crucial difference from `or`\n\n orElse (Err \"Oh!\") (Ok 5) == Ok 5\n\n orElse (Ok 4) (Err \"No!\") == Ok 4\n\n orElse (Err \"Oh!\") (Err \"No!\") == Err \"Oh!\" -- also different from `or`\n\nAlso:\n\n String.toInt \"Hello\"\n |> orElse (String.toInt \"42\")\n\n","type":"Result.Result e a -> Result.Result e a -> Result.Result e a"},{"name":"orElseLazy","comment":" Piping-friendly version of `orLazy`. The first argument will only\nbe evaluated if the second argument is an `Err`. Example use:\n\n String.toInt \"Hello\"\n |> orElseLazy (\\() -> String.toInt \"42\")\n\n","type":"(() -> Result.Result e a) -> Result.Result e a -> Result.Result e a"},{"name":"orLazy","comment":" Non-strict version of `or`. The second argument will only be\nevaluated if the first argument is an `Err`.\n","type":"Result.Result e a -> (() -> Result.Result e a) -> Result.Result e a"},{"name":"partition","comment":" Partition a list of Results into two lists of values (successes\nand failures), much as List.partition takes a predicate and splits\na list based on whether the predicate indicates success or failure.\n\n partition ( Ok 4, Err \"no\", Err \"hi\" ) == ( [ 4 ], [ \"no\", \"hi\" ] )\n\n partition ( Err 7.1, Ok 'k', Err 9.0, Ok 'p' ) == ( [ 'k', 'p' ], [ 7.1, 9.0 ] )\n\n","type":"List.List (Result.Result e a) -> ( List.List a, List.List e )"},{"name":"singleton","comment":" Create a `singleton` from a value to an `Result` with a `Ok`\nof the same type. Also known as `pure`. You can use the `Err`\nconstructor for a singleton of the `Err` variety.\n\n singleton 2 == Ok 2\n\n","type":"a -> Result.Result e a"},{"name":"toTask","comment":" Convert a `Result` to a `Task` that will fail or succeed immediately.\n\n toTask (Ok 4) == Task.succeed 4\n\n toTask (Err \"msg\") == Task.fail \"msg\"\n\nThis can be helpful when the value of a succeeding Task needs to be decoded, but\na failure to decode should result in a failing `Task`, not a succeeding Task\ncontaining a `Result.Err`:\n\nandThenDecode : (a -> Result x b) -> Task x a -> Task x b\nandThenDecode decode =\nTask.andThen (decode >> Result.Extra.toTask)\n\n","type":"Result.Result x a -> Task.Task x a"},{"name":"unpack","comment":" Convert a `Result e a` to a `b` by applying either the first\nfunction if the `Result` is an `Err` or the second function if the\n`Result` is `Ok`. Both of these functions must return the same type.\n","type":"(e -> b) -> (a -> b) -> Result.Result e a -> b"},{"name":"unwrap","comment":" Convert a `Result e a` to a `b` by applying a function if\nthe `Result` is `Ok` or using the provided default value if it\nis an `Err`.\n","type":"b -> (a -> b) -> Result.Result e a -> b"}],"binops":[]},{"name":"String.Extra","comment":" Additional functions for working with Strings\n\n\n## Change words casing\n\n@docs toSentenceCase, toTitleCase, decapitalize\n\n\n## Inflector functions\n\nFunctions borrowed from the Rails Inflector class\n\n@docs camelize, classify, underscored, dasherize, humanize\n\n\n## Replace and Splice\n\n@docs replaceSlice, insertAt, nonEmpty, nonBlank, removeAccents\n\n\n## Splitting\n\n@docs break, softBreak\n\n\n## Wrapping\n\n@docs wrap, wrapWith, softWrap, softWrapWith, quote, surround\n\n\n## Checks\n\n@docs isBlank, countOccurrences\n\n\n## Formatting\n\n@docs clean, unquote, unsurround, unindent, ellipsis, softEllipsis, ellipsisWith, stripTags, pluralize\n\n\n## Converting Lists\n\n@docs toSentence, toSentenceOxford\n\n\n## Finding\n\n@docs rightOf, leftOf, rightOfBack, leftOfBack\n\n\n## Converting UTF-32\n\n@docs toCodePoints, fromCodePoints\n\n","unions":[],"aliases":[],"values":[{"name":"break","comment":" Break a string into a list of strings of a specified maximum length.\n\n break 10 \"The quick brown fox\" == [ \"The quick \", \"brown fox\" ]\n\n break 2 \"\" == [ \"\" ]\n\n","type":"Basics.Int -> String.String -> List.List String.String"},{"name":"camelize","comment":" Convert an underscored or dasherized string to a camelized one.\n\n camelize \"-moz-transform\" == \"MozTransform\"\n\n","type":"String.String -> String.String"},{"name":"classify","comment":" Convert a string to a camelized string starting with an uppercase letter.\nAll non-word characters will be stripped out of the original string.\n\n classify \"some_class_name\" == \"SomeClassName\"\n\n classify \"myLittleCamel.class.name\" == \"MyLittleCamelClassName\"\n\n","type":"String.String -> String.String"},{"name":"clean","comment":" Trim the whitespace of both sides of the string and compress\nrepeated whitespace internally to a single whitespace char.\n\n clean \" The quick brown fox \" == \"The quick brown fox\"\n\n","type":"String.String -> String.String"},{"name":"countOccurrences","comment":" Return the number of occurrences of a substring in another string.\n\n countOccurrences \"Hello\" \"Hello World\" == 1\n\n countOccurrences \"o\" \"Hello World\" == 2\n\n","type":"String.String -> String.String -> Basics.Int"},{"name":"dasherize","comment":" Return a string joined by dashes after separating it by its uppercase characters.\nAny sequence of spaces or underscores will also be converted to a single dash.\nThe final string will be lowercased.\n\n dasherize \"SomeClassName\" --> \"some-class-name\"\n\n dasherize \"some_class_name\" --> \"some-class-name\"\n\n dasherize \"someClass name\" --> \"some-class-name\"\n\n","type":"String.String -> String.String"},{"name":"decapitalize","comment":" Decapitalize the first letter of a string.\n\n decapitalize \"This is a phrase\" == \"this is a phrase\"\n\n decapitalize \"Hello, World\" == \"hello, World\"\n\n","type":"String.String -> String.String"},{"name":"ellipsis","comment":" Truncate the string at the specified length if the string is\nlonger than the specified length, and replace the end of the truncated\nstring with `\"...\"`, such that the resulting string is of the\nspecified length.\n\nThe resulting string will have at most the specified length.\n\n ellipsis 5 \"Hello World\" == \"He...\"\n\n ellipsis 10 \"Hello World\" == \"Hello W...\"\n\n ellipsis 10 \"Hello\" == \"Hello\"\n\n ellipsis 8 \"Hello World\" == \"Hello...\"\n\n","type":"Basics.Int -> String.String -> String.String"},{"name":"ellipsisWith","comment":" Truncate the second string at the specified length if the string is\nlonger than the specified length, and replace the end of the truncated\nstring with the first string, such that the resulting string is of the\nspecified length.\n\nThe resulting string will have at most the specified length.\n\n ellipsisWith 5 \" ..\" \"Hello World\" == \"He ..\"\n\n ellipsisWith 10 \" ..\" \"Hello World\" == \"Hello W ..\"\n\n ellipsisWith 10 \" ..\" \"Hello\" == \"Hello\"\n\n ellipsisWith 8 \" ..\" \"Hello World\" == \"Hello ..\"\n\n","type":"Basics.Int -> String.String -> String.String -> String.String"},{"name":"fromCodePoints","comment":" Convert a list of UTF-32 code points into a string. Inverse of\n`toCodePoints`.\n\n fromCodePoints [ 97, 98, 99 ] == \"abc\"\n\n fromCodePoints [ 169, 167, 960 ] == \"©§π\"\n\n fromCodePoints [ 128169, 33 ] == \"💩!\"\n\n`fromCodePoints codePoints` is equivalent to:\n\n String.fromList (List.map Char.fromCode codePoints)\n\n","type":"List.List Basics.Int -> String.String"},{"name":"humanize","comment":" Convert an underscored, camelized, or dasherized string into one that can be\nread by humans. Also remove beginning and ending whitespace, and removes the\npostfix '\\_id'. The first character will be capitalized.\n\n humanize \"this_is_great\" == \"This is great\"\n humanize \"ThisIsGreat\" = \"This is great\"\n humanize \"this-is-great\" = \"This is great\"\n humanize \"author_id\" = \"Author\"\n\n","type":"String.String -> String.String"},{"name":"insertAt","comment":" Insert a substring at the specified index.\n\n insertAt \"world\" 6 \"Hello \" == \"Hello world\"\n\n","type":"String.String -> Basics.Int -> String.String -> String.String"},{"name":"isBlank","comment":" Test if a string is empty or only contains whitespace.\n\n isBlank \"\" == True\n\n isBlank \"\\n\" == True\n\n isBlank \" \" == True\n\n isBlank \" a\" == False\n\n","type":"String.String -> Basics.Bool"},{"name":"leftOf","comment":" Search a string from left to right for a pattern and return a substring\nconsisting of the characters in the string that are to the left of the pattern.\n\n leftOf \"_\" \"This_is_a_test_string\" == \"This\"\n\n","type":"String.String -> String.String -> String.String"},{"name":"leftOfBack","comment":" Search a string from right to left for a pattern and return a substring\nconsisting of the characters in the string that are to the left of the pattern.\n\n leftOfBack \"_\" \"This_is_a_test_string\" == \"This_is_a_test\"\n\n","type":"String.String -> String.String -> String.String"},{"name":"nonBlank","comment":" Convert a string to a Nothing when blank.\n\n nonBlank \"\" == Nothing\n\n nonBlank \" \" == Nothing\n\n nonBlank \"Hello world\" == Just \"Hello world\"\n\n","type":"String.String -> Maybe.Maybe String.String"},{"name":"nonEmpty","comment":" Convert a string to a Nothing when empty.\n\n nonEmpty \"\" == Nothing\n\n nonEmpty \"Hello world\" == Just \"Hello world\"\n\n","type":"String.String -> Maybe.Maybe String.String"},{"name":"pluralize","comment":" Given a number, a singular string, and a plural string, return the number\nfollowed by a space, followed by either the singular string if the number was 1,\nor the plural string otherwise.\n\n pluralize \"elf\" \"elves\" 2 == \"2 elves\"\n\n pluralize \"elf\" \"elves\" 1 == \"1 elf\"\n\n pluralize \"elf\" \"elves\" 0 == \"0 elves\"\n\n","type":"String.String -> String.String -> Basics.Int -> String.String"},{"name":"quote","comment":" Add quotes to a string.\n\n quote \"foo\" == \"\\\"foo\\\"\"\n\n","type":"String.String -> String.String"},{"name":"removeAccents","comment":" Remove accents from string.\n\n removeAccents \"andré\" == \"andre\"\n\n removeAccents \"Atenção\" == \"Atencao\"\n\n","type":"String.String -> String.String"},{"name":"replaceSlice","comment":" Replace text within a portion of a string given a substitution\nstring, a start index and an end index. The substitution includes the character\nat the start index but not the one at the end index.\n\n replaceSlice \"Sue\" 4 7 \"Hi, Bob\" == \"Hi, Sue\"\n\n replaceSlice \"elephants\" 0 6 \"snakes on a plane!\" == \"elephants on a plane!\"\n\n replaceSlice \"under\" 7 9 \"snakes on a plane!\" == \"snakes under a plane!\"\n\n","type":"String.String -> Basics.Int -> Basics.Int -> String.String -> String.String"},{"name":"rightOf","comment":" Search a string from left to right for a pattern and return a substring\nconsisting of the characters in the string that are to the right of the pattern.\n\n rightOf \"_\" \"This_is_a_test_string\" == \"is_a_test_string\"\n\n","type":"String.String -> String.String -> String.String"},{"name":"rightOfBack","comment":" Search a string from right to left for a pattern and return a substring\nconsisting of the characters in the string that are to the right of the pattern.\n\n rightOfBack \"_\" \"This_is_a_test_string\" == \"string\"\n\n","type":"String.String -> String.String -> String.String"},{"name":"softBreak","comment":" Break a string into a list of strings of a specified maximum length,\nwithout truncating words.\n\n softBreak 6 \"The quick brown fox\" == [ \"The quick\", \" brown\", \" fox\" ]\n\n","type":"Basics.Int -> String.String -> List.List String.String"},{"name":"softEllipsis","comment":" Truncate the string at the last complete word less than or equal to\nthe specified length and append `\"...\"`. When the specified length is\nless than the length of the first word, the ellipsis is appended to the\nfirst word. When the specified length is greater than or equal to the\nlength of the string, an identical string is returned.\n\nIn contrast to `ellipsis`, this function will not produce incomplete\nwords, and the resulting string can exceed the specified length. In\naddition, it removes trailing whitespace and punctuation characters at\nthe end of the truncated string.\n\n softEllipsis 1 \"Hello, World\" == \"Hello...\"\n\n softEllipsis 5 \"Hello, World\" == \"Hello...\"\n\n softEllipsis 6 \"Hello, World\" == \"Hello...\"\n\n softEllipsis 15 \"Hello, cruel world\" == \"Hello, cruel...\"\n\n softEllipsis 10 \"Hello\" == \"Hello\"\n\n","type":"Basics.Int -> String.String -> String.String"},{"name":"softWrap","comment":" Chop a given string into parts of a given width without breaking words apart,\nand then separate them using a new line.\n\n softWrap 7 \"My very long text\" === \"My very\\nlong text\"\n\n softWrap 3 \"Hello World\" === \"Hello \\nWorld\"\n\n softWrap 100 \"Too short\" === \"Too short\"\n\n","type":"Basics.Int -> String.String -> String.String"},{"name":"softWrapWith","comment":" Chop a given string into parts of a given width without breaking words apart,\nand then separate them using the given separator.\n\n softWrapWith 7 \"...\" \"My very long text\" === \"My very...long text\"\n\n softWrapWith 3 \"\\n\" \"Hello World\" === \"Hello \\nWorld\"\n\n softWrapWith 100 \"\\t\" \"Too short\" === \"Too short\"\n\n","type":"Basics.Int -> String.String -> String.String -> String.String"},{"name":"stripTags","comment":" Remove all HTML tags from the string, preserving the text inside them.\n\n stripTags \"a link\" == \"a link\"\n stripTags \" == \"alert('hello world!')\"\n\n","type":"String.String -> String.String"},{"name":"surround","comment":" Surround a string with another string.\n\n surround \"bar\" \"foo\" == \"barfoobar\"\n\n","type":"String.String -> String.String -> String.String"},{"name":"toCodePoints","comment":" Convert a string into a list of UTF-32 code points.\n\n toCodePoints \"abc\" == [ 97, 98, 99 ]\n\n toCodePoints \"©§π\" == [ 169, 167, 960 ]\n\n toCodePoints \"💩!\" == [ 128169, 33 ]\n\nNote that code points do not necessarily correspond to logical/visual\ncharacters, since it is possible for things like accented characters to be\nrepresented as two separate UTF-32 code points (a base character and a\ncombining accent).\n\n`toCodePoints string` is equivalent to:\n\n List.map Char.toCode (String.toList string)\n\n","type":"String.String -> List.List Basics.Int"},{"name":"toSentence","comment":" Convert a list of strings into a human-readable list.\n\n toSentence [] == \"\"\n\n toSentence [ \"lions\" ] == \"lions\"\n\n toSentence [ \"lions\", \"tigers\" ] == \"lions and tigers\"\n\n toSentence [ \"lions\", \"tigers\", \"bears\" ] == \"lions, tigers and bears\"\n\n","type":"List.List String.String -> String.String"},{"name":"toSentenceCase","comment":" Capitalize the first letter of a string.\n\n toSentenceCase \"this is a phrase\" == \"This is a phrase\"\n\n toSentenceCase \"hello, world\" == \"Hello, world\"\n\n","type":"String.String -> String.String"},{"name":"toSentenceOxford","comment":" Convert a list of strings into a human-readable list using an oxford comma.\n\n toSentenceOxford [] == \"\"\n\n toSentenceOxford [ \"lions\" ] == \"lions\"\n\n toSentenceOxford [ \"lions\", \"tigers\" ] == \"lions and tigers\"\n\n toSentenceOxford [ \"lions\", \"tigers\", \"bears\" ] == \"lions, tigers, and bears\"\n\n","type":"List.List String.String -> String.String"},{"name":"toTitleCase","comment":" Capitalize the first character of each word in a string.\n\n toTitleCase \"this is a phrase\" == \"This Is A Phrase\"\n\n toTitleCase \"hello, world\" == \"Hello, World\"\n\n","type":"String.String -> String.String"},{"name":"underscored","comment":" Return a string joined by underscores after separating it by its uppercase characters.\nAny sequence of spaces or dashes will also be converted to a single underscore.\nThe final string will be lowercased.\n\n underscored \"SomeClassName\" == \"some_class_name\"\n underscored \"some-class-name\" == \"some_class_name\"\n underscored \"SomeClass name\" == \"some_class_name\n\n","type":"String.String -> String.String"},{"name":"unindent","comment":" Remove the shortest sequence of leading spaces or tabs on each line\nof the string, so that at least one of the lines will not have any\nleading spaces nor tabs and the rest of the lines will have the same\namount of indentation removed.\n\n unindent \" Hello\\n World \" == \"Hello\\n World\"\n\n unindent \"\\t\\tHello\\n\\t\\t\\t\\tWorld\" == \"Hello\\n\\t\\tWorld\"\n\n","type":"String.String -> String.String"},{"name":"unquote","comment":" Remove quotes that surround a string.\n\n unquote \"\\\"foo\\\"\" == \"foo\"\n\n unquote \"\\\"foo\\\"bar\\\"\"\n\n","type":"String.String -> String.String"},{"name":"unsurround","comment":" Remove surrounding strings from another string.\n\n unsurround \"foo\" \"foobarfoo\" == \"bar\"\n\n","type":"String.String -> String.String -> String.String"},{"name":"wrap","comment":" Chop a given string into parts of a given width, separating them with a\nnew line.\n\n wrap 7 \"My very long text\" === \"My very\\nlong te\\nxt\"\n\n wrap 100 \"Too short\" === \"Too short\"\n\n","type":"Basics.Int -> String.String -> String.String"},{"name":"wrapWith","comment":" Separate a string into parts of a given width, using a given separator.\n\nLook at `wrap` if you just want to wrap using newlines.\n\n wrapWith 7 \"\\n\" \"My very long text\" === \"My very\\nlong text\"\n\n wrapWith 100 \"\\n\" \"Too short\" === \"Too short\"\n\n","type":"Basics.Int -> String.String -> String.String -> String.String"}],"binops":[]}] \ No newline at end of file +[{"name":"Array.Extra","comment":" Convenience functions for working with `Array`\n\n\n# observe\n\n@docs all, any, member\n\n\n# alter\n\n@docs reverse, intersperse\n@docs update, pop, removeAt, insertAt\n\n\n## filter\n\n@docs removeWhen, filterMap\n\n\n## part\n\n@docs sliceFrom, sliceUntil, splitAt, unzip\n\n\n## combine\n\n@docs interweave, apply, map2, map3, map4, map5, zip, zip3\n\n\n## resize\n\n@docs resizelRepeat, resizerRepeat, resizelIndexed, resizerIndexed\n\n\n# transform\n\n@docs mapToList, indexedMapToList\n\n","unions":[],"aliases":[],"values":[{"name":"all","comment":" Whether all elements satisfy a given test.\n\n import Array exposing (fromList, empty)\n\n fromList [ 2, 4 ] |> all (\\x -> x < 5)\n --> True\n\n fromList [ 4, 16 ] |> all (\\x -> x < 5)\n --> False\n\n empty |> all (\\x -> x < 5)\n --> True\n\n","type":"(element -> Basics.Bool) -> Array.Array element -> Basics.Bool"},{"name":"any","comment":" Whether at least some elements satisfy a given test.\n\n import Array exposing (fromList, empty)\n\n fromList [ 6, 3 ] |> any (\\x -> x < 5)\n --> True\n\n fromList [ 12, 33 ] |> any (\\x -> x < 5)\n --> False\n\n empty |> any (\\x -> x < 5)\n --> False\n\n","type":"(element -> Basics.Bool) -> Array.Array element -> Basics.Bool"},{"name":"apply","comment":" Apply a given `Array` of changes to all elements.\nIf one `Array` is longer, its extra elements are not used.\n\n import Array exposing (fromList, repeat)\n\n repeat 5 100\n |> apply\n (fromList\n [ \\x -> -x, identity, (+) 10 ]\n )\n --> fromList [ -100, 100, 110 ]\n\n","type":"Array.Array (a -> b) -> Array.Array a -> Array.Array b"},{"name":"filterMap","comment":" Try transforming all elements but only keep the successes.\n\n import Array exposing (fromList)\n\n fromList [ \"3\", \"4.0\", \"5\", \"hats\" ]\n |> filterMap String.toInt\n --> fromList [ 3, 5 ]\n\n","type":"(a -> Maybe.Maybe b) -> Array.Array a -> Array.Array b"},{"name":"indexedMapToList","comment":" Transform all elements with their indexes as the first argument\nand collect the result in a `List`.\n\n import Array exposing (Array, fromList)\n import Html exposing (Html)\n\n type alias Exercise =\n { name : String }\n\n exerciseRender : Int -> Exercise -> Html msg\n exerciseRender index =\n \\exercise ->\n String.concat\n [ \"Exercise #\"\n , String.fromInt (index + 1)\n , \" - \"\n , exercise.name\n ]\n |> Html.text\n\n exercisesRender : Array Exercise -> Html msg\n exercisesRender =\n indexedMapToList renderExercise\n >> Html.div []\n\n","type":"(Basics.Int -> element -> mappedElement) -> Array.Array element -> List.List mappedElement"},{"name":"insertAt","comment":" Insert an element at a given index.\nIf the index is out of bounds, nothing is changed.\n\n import Array exposing (fromList)\n\n fromList [ 'a', 'c' ] |> insertAt 1 'b'\n --> fromList [ 'a', 'b', 'c' ]\n\n fromList [ 'a', 'c' ] |> insertAt -1 'b'\n --> fromList [ 'a', 'c' ]\n\n fromList [ 'a', 'c' ] |> insertAt 100 'b'\n --> fromList [ 'a', 'c' ]\n\n","type":"Basics.Int -> element -> Array.Array element -> Array.Array element"},{"name":"intersperse","comment":" Place a value between all elements.\n\n import Array exposing (fromList)\n\n fromList [ \"turtles\", \"turtles\", \"turtles\" ]\n |> intersperse \"on\"\n --> fromList\n --> [ \"turtles\", \"on\", \"turtles\", \"on\", \"turtles\" ]\n\nTo interlace an `Array`, [`interweave`](#interweave).\n\n","type":"a -> Array.Array a -> Array.Array a"},{"name":"interweave","comment":" Place all elements of a given `Array` between all current elements.\nExtra elements of either `Array` are glued to the end without anything in between.\n\n import Array exposing (fromList, repeat)\n\n fromList [ \"turtles\", \"turtles\", \"turtles\" ]\n |> interweave (repeat 2 \"on\")\n --> fromList [ \"turtles\", \"on\", \"turtles\", \"on\", \"turtles\" ]\n\n fromList [ \"turtles\", \"turtles\", \"turtles\" ]\n |> interweave (repeat 5 \"on\")\n --> fromList [ \"turtles\", \"on\", \"turtles\", \"on\", \"turtles\", \"on\", \"on\", \"on\" ]\n\n fromList [ \"turtles\", \"turtles\", \"turtles\" ]\n |> interweave (repeat 1 \"on\")\n --> fromList [ \"turtles\", \"on\", \"turtles\", \"turtles\" ]\n\n","type":"Array.Array element -> Array.Array element -> Array.Array element"},{"name":"map2","comment":" Combine the elements of two `Array`s with a given function.\nIf one `Array` is longer, its extra elements are not used.\n\n import Array exposing (fromList)\n\n map2 (\\a b -> a + b)\n (fromList [ 1, 2, 3 ])\n (fromList [ 1, 2, 3, 4 ])\n --> fromList [ 2, 4, 6 ]\n\n map2 Tuple.pair\n (fromList [ 1, 2, 3 ])\n (fromList [ 'a', 'b' ])\n --> fromList [ ( 1, 'a' ), ( 2, 'b' ) ]\n\nNote: [`zip`](Array-Extra#zip) can be used instead of `map2 Tuple.pair`.\n\n","type":"(a -> b -> combined) -> Array.Array a -> Array.Array b -> Array.Array combined"},{"name":"map3","comment":" Combine the elements of three `Array`s with the given function. See [`map2`](Array-Extra#map2).\n\nNote: [`zip3`](Array-Extra#zip3) can be used instead of `map3 (\\a b c -> ( a, b, c ))`.\n\n","type":"(a -> b -> c -> combined) -> Array.Array a -> Array.Array b -> Array.Array c -> Array.Array combined"},{"name":"map4","comment":" Combine the elements of four `Array`s with the given function. See [`map2`](Array-Extra#map2).\n","type":"(a -> b -> c -> d -> combined) -> Array.Array a -> Array.Array b -> Array.Array c -> Array.Array d -> Array.Array combined"},{"name":"map5","comment":" Combine the elements of five `Array`s with the given function. See [`map2`](Array-Extra#map2).\n","type":"(a -> b -> c -> d -> e -> combined) -> Array.Array a -> Array.Array b -> Array.Array c -> Array.Array d -> Array.Array e -> Array.Array combined"},{"name":"mapToList","comment":" Apply a function to the elements in the array and collect the result in a List.\n\n import Array exposing (fromList)\n import Html\n\n fromList [ \"a\", \"b\", \"c\" ]\n |> mapToList Html.text\n --> [ Html.text \"a\", Html.text \"b\", Html.text \"c\" ]\n\n","type":"(a -> b) -> Array.Array a -> List.List b"},{"name":"member","comment":" Whether a given value is contained.\n\n import Array exposing (fromList)\n\n fromList [ \"Leonardo\", \"Michelangelo\", \"Donatello\", \"Raphael\" ]\n |> member \"Donatello\"\n --> True\n\n fromList [ \"Leonardo\", \"Michelangelo\" ]\n |> member \"Raphael\"\n --> False\n\nFor checking if some aspect is present, use [`any`](#any).\n\n","type":"element -> Array.Array element -> Basics.Bool"},{"name":"pop","comment":" Remove the last element.\n\n import Array exposing (fromList, empty)\n\n fromList [ 1, 2, 3 ] |> pop\n --> fromList [ 1, 2 ]\n\n empty |> pop\n --> empty\n\n","type":"Array.Array a -> Array.Array a"},{"name":"removeAt","comment":" Remove the element at a given index.\nIf the index is out of bounds, nothing is changed.\n\n import Array exposing (fromList)\n\n fromList [ 1, 2, 3, 4 ] |> removeAt 2\n --> fromList [ 1, 2, 4 ]\n\n fromList [ 1, 2, 3, 4 ] |> removeAt -1\n --> fromList [ 1, 2, 3, 4 ]\n\n fromList [ 1, 2, 3, 4 ] |> removeAt 100\n --> fromList [ 1, 2, 3, 4 ]\n\n","type":"Basics.Int -> Array.Array element -> Array.Array element"},{"name":"removeWhen","comment":" Only keep elements which fail to satisfy a given predicate.\nThis is equivalent to `Array.filter (not << predicate)`.\n\n import Array exposing (fromList)\n\n fromList [ -1, 92, 0, 14, -3 ]\n |> removeWhen (\\x -> x < 0)\n --> fromList [ 92, 0, 14 ]\n\n","type":"(element -> Basics.Bool) -> Array.Array element -> Array.Array element"},{"name":"resizelIndexed","comment":" Resize from the left, padding the right-hand side with a given value based on index.\n\n import Array exposing (fromList, empty)\n\n fromList [ 'a', 'b', 'c' ]\n |> resizelIndexed 5 toLetterInAlphabet\n --> fromList [ 'a', 'b', 'c', 'd', 'e' ]\n\n fromList [ 'a', 'b', 'c' ]\n |> resizelIndexed 2 toLetterInAlphabet\n --> fromList [ 'a', 'b' ]\n\n fromList [ 'a', 'b', 'c' ]\n |> resizelIndexed -1 toLetterInAlphabet\n --> empty\n\n toLetterInAlphabet : Int -> Char\n toLetterInAlphabet inAlphabet =\n ('a' |> Char.toCode) + inAlphabet\n |> Char.fromCode\n\n","type":"Basics.Int -> (Basics.Int -> element) -> Array.Array element -> Array.Array element"},{"name":"resizelRepeat","comment":" Resize from the left, padding the right-hand side with a given value.\n\n import Array exposing (fromList, empty)\n\n fromList [ 1, 2 ] |> resizelRepeat 4 0\n --> fromList [ 1, 2, 0, 0 ]\n\n fromList [ 1, 2, 3 ] |> resizelRepeat 2 0\n --> fromList [ 1, 2 ]\n\n fromList [ 1, 2 ] |> resizelRepeat -1 0\n --> empty\n\n","type":"Basics.Int -> element -> Array.Array element -> Array.Array element"},{"name":"resizerIndexed","comment":" Resize from the right, padding the left-hand side with a given value based on index.\n\n import Array exposing (fromList, empty)\n\n fromList [ 10, 25, 36 ]\n |> resizerIndexed 5 (\\n -> n * 5)\n --> fromList [ 0, 5, 10, 25, 36 ]\n\n fromList [ 10, 25, 36 ]\n |> resizerIndexed 2 (\\n -> n * 5)\n --> fromList [ 25, 36 ]\n\n fromList [ 10, 25, 36 ]\n |> resizerIndexed -1 (\\n -> n * 5)\n --> empty\n\n","type":"Basics.Int -> (Basics.Int -> element) -> Array.Array element -> Array.Array element"},{"name":"resizerRepeat","comment":" Resize from the right, padding the left-hand side with a given value.\n\n import Array exposing (fromList, empty)\n\n fromList [ 1, 2 ] |> resizerRepeat 4 0\n --> fromList [ 0, 0, 1, 2 ]\n\n fromList [ 1, 2, 3 ] |> resizerRepeat 2 0\n --> fromList [ 2, 3 ]\n\n fromList [ 1, 2 ] |> resizerRepeat -1 0\n --> empty\n\n","type":"Basics.Int -> element -> Array.Array element -> Array.Array element"},{"name":"reverse","comment":" Flip the element order.\n\n import Array exposing (fromList)\n\n fromList [ 1, 2, 3, 4 ] |> reverse\n --> fromList [ 4, 3, 2, 1 ]\n\n","type":"Array.Array element -> Array.Array element"},{"name":"sliceFrom","comment":" Drop a given number of elements from the start.\nIn other words, slice the `Array` from an index until the very end.\nGiven a negative argument, count the end of the slice from the end.\n\n import Array exposing (fromList)\n\n fromList (List.range 0 6) |> sliceFrom 3\n --> fromList [ 3, 4, 5, 6 ]\n\n fromList (List.range 0 6) |> sliceFrom -3\n --> fromList [ 4, 5, 6 ]\n\n","type":"Basics.Int -> Array.Array a -> Array.Array a"},{"name":"sliceUntil","comment":" Take a number of elements from the start.\nIn other words, slice the `Array` from the very beginning until not including the index.\nGiven a negative argument, count the beginning of the slice from the end.\n\n import Array exposing (fromList)\n\n fromList (List.range 0 6) |> sliceUntil 3\n --> fromList [ 0, 1, 2 ]\n\n fromList (List.range 0 6) |> sliceUntil -3\n --> fromList [ 0, 1, 2, 3 ]\n\n","type":"Basics.Int -> Array.Array a -> Array.Array a"},{"name":"splitAt","comment":" Split into two `Array`s, the first ending before and the second starting with a given index.\n\n import Array exposing (fromList, empty)\n\n fromList [ 1, 2, 3, 4 ] |> splitAt 2\n --> ( fromList [ 1, 2 ], fromList [ 3, 4 ] )\n\n fromList [ 1, 2, 3, 4 ] |> splitAt 100\n --> ( fromList [ 1, 2, 3, 4 ], empty )\n\n fromList [ 1, 2, 3, 4 ] |> splitAt -1\n --> ( empty, fromList [ 1, 2, 3, 4 ] )\n\n","type":"Basics.Int -> Array.Array element -> ( Array.Array element, Array.Array element )"},{"name":"unzip","comment":" Split all tuple elements into a tuple of one `Array` with the first and one with the second values.\n\n import Array exposing (fromList)\n\n unzip\n (fromList\n [ ( 1, 'a' ), ( 2, 'b' ), ( 3, 'c' ) ]\n )\n --> ( fromList [ 1, 2, 3 ]\n --> , fromList [ 'a', 'b', 'c' ]\n --> )\n\n","type":"Array.Array ( elementFirst, elementSecond ) -> ( Array.Array elementFirst, Array.Array elementSecond )"},{"name":"update","comment":" Update the element at a given index based on its current value.\nIf the index is out of bounds, nothing is changed.\n\n import Array exposing (fromList)\n\n fromList [ 1, 2, 3 ] |> update 1 (\\n -> n + 10)\n --> fromList [ 1, 12, 3 ]\n\n fromList [ 1, 2, 3 ] |> update 4 (\\n -> n + 10)\n --> fromList [ 1, 2, 3 ]\n\n fromList [ 1, 2, 3 ] |> update -1 (\\n -> n + 10)\n --> fromList [ 1, 2, 3 ]\n\n","type":"Basics.Int -> (a -> a) -> Array.Array a -> Array.Array a"},{"name":"zip","comment":" Combine the elements of two `Array`s into tuples.\nIf one is longer, its extra elements are not used.\n\n import Array exposing (fromList)\n\n zip\n (fromList [ 1, 2, 3 ])\n (fromList [ 'a', 'b' ])\n --> fromList [ ( 1, 'a' ), ( 2, 'b' ) ]\n\n","type":"Array.Array firstElement -> Array.Array secondElement -> Array.Array ( firstElement, secondElement )"},{"name":"zip3","comment":" Zip the elements of three `Array`s into 3-tuples.\nOnly the indexes of the shortest `Array` are used.\n\n import Array exposing (fromList)\n\n zip3\n (fromList [ 1, 2, 3 ])\n (fromList [ 'a', 'b' ])\n (fromList [ \"a\", \"b\", \"c\", \"d\" ])\n --> fromList\n --> [ ( 1, 'a', \"a\" )\n --> , ( 2, 'b', \"b\" )\n --> ]\n\n","type":"Array.Array firstElement -> Array.Array secondElement -> Array.Array thirdElement -> Array.Array ( firstElement, secondElement, thirdElement )"}],"binops":[]},{"name":"Basics.Extra","comment":" Additional basic functions.\n\n\n# Tuples\n\n@docs swap\n\n\n# Numbers\n\n@docs maxSafeInteger, minSafeInteger, isSafeInteger\n\n\n# Math\n\n@docs atMost, atLeast\n@docs safeDivide, safeIntegerDivide\n@docs safeModBy, safeRemainderBy, fractionalModBy\n\n\n# Angles\n\n@docs inDegrees, inRadians, inTurns\n\n\n# Higher-Order Helpers\n\n@docs flip, curry, uncurry\n\n\n# Comparison & Ordering\n\n@docs orderBy, toOrder, toOrderDesc\n\n","unions":[],"aliases":[],"values":[{"name":"atLeast","comment":" Defines a lower bound for a variable.\n\n -42 |> atLeast 0 --> 0\n\n 42 |> atLeast 0 --> 42\n\n","type":"comparable -> comparable -> comparable"},{"name":"atMost","comment":" Defines an upper bound for a variable.\n\n 42 |> atMost 0 --> 0\n\n -42 |> atMost 0 --> -42\n\n","type":"comparable -> comparable -> comparable"},{"name":"curry","comment":" Change how arguments are passed to a function.\nThis splits paired arguments into two separate arguments.\n","type":"(( a, b ) -> c) -> a -> b -> c"},{"name":"flip","comment":" Flip the order of the first two arguments to a function.\n","type":"(a -> b -> c) -> b -> a -> c"},{"name":"fractionalModBy","comment":" Perform [modular arithmetic](https://en.wikipedia.org/wiki/Modular_arithmetic)\ninvolving floating point numbers.\n\nThe sign of the result is the same as the sign of the `modulus`\nin `fractionalModBy modulus x`.\n\n fractionalModBy 2.5 5 --> 0\n\n fractionalModBy 2 4.5 == 0.5\n\n fractionalModBy 2 -4.5 == 1.5\n\n fractionalModBy -2 4.5 == -1.5\n\n","type":"Basics.Float -> Basics.Float -> Basics.Float"},{"name":"inDegrees","comment":" Convert standard Elm angles (radians) to degrees.\n\n inDegrees (turns 2) --> 720\n\n inDegrees pi --> 180\n\n","type":"Basics.Float -> Basics.Float"},{"name":"inRadians","comment":" Convert standard Elm angles (radians) to radians.\n\n inRadians (degrees 90) == pi / 2\n\n inRadians (turns 1) == 2 * pi\n\n","type":"Basics.Float -> Basics.Float"},{"name":"inTurns","comment":" Convert standard Elm angles (radians) to turns. One turn is equal to 360°.\n\n inTurns (degrees 180) == 0.5\n\n inTurns (3 * pi) == 1.5\n\n","type":"Basics.Float -> Basics.Float"},{"name":"isSafeInteger","comment":" Checks if a given integer is within the safe range, meaning it is between\n`-(2^53 - 1)` and `2^53 - 1`.\n\n isSafeInteger 5 --> True\n\n isSafeInteger maxSafeInteger --> True\n\n isSafeInteger (maxSafeInteger + 1) --> False\n\n","type":"Basics.Int -> Basics.Bool"},{"name":"maxSafeInteger","comment":" The maximum _safe_ value for an integer, defined as `2^53 - 1`. Anything\nlarger than that and behaviour becomes mathematically unsound.\n\n maxSafeInteger + 1 --> maxSafeInteger + 2\n\n","type":"number"},{"name":"minSafeInteger","comment":" The minimum _safe_ value for an integer, defined as `-(2^53 - 1)`. Anything\nsmaller than that, and behaviour becomes mathematically unsound.\n\n minSafeInteger - 1 --> minSafeInteger - 2\n\n","type":"number"},{"name":"orderBy","comment":" Create an ordering function that can be used to sort\nlists by multiple dimensions, by flattening multiple ordering functions into one.\n\nThis is equivalent to `ORDER BY` in SQL. The ordering function will order\nits inputs based on the order that they appear in the `List (a -> a -> Order)` argument.\n\n type alias Pen =\n { model : String\n , tipWidthInMillimeters : Float\n }\n\n pens : List Pen\n pens =\n [ Pen \"Pilot Hi-Tec-C Gel\" 0.4\n , Pen \"Morning Glory Pro Mach\" 0.38\n , Pen \"Pilot Hi-Tec-C Coleto\" 0.5\n ]\n\n order : Pen -> Pen -> Order\n order =\n orderBy [ toOrder .tipWidthInMillimeters, toOrder .model ]\n\n List.sortWith order pens\n --> [ Pen \"Morning Glory Pro Mach\" 0.38\n --> , Pen \"Pilot Hi-Tec-C Gel\" 0.4\n --> , Pen \"Pilot Hi-Tec-C Coleto\" 0.5\n --> ]\n\nIf our `Pen` type alias above was represented a row in a database table, our `order` function as defined above would be equivalent\nto this SQL clause:\n\n ORDER BY tipWidthInMillimeters, model\n\n","type":"List.List (a -> a -> Basics.Order) -> a -> a -> Basics.Order"},{"name":"safeDivide","comment":" Perform floating-point division (like Elm's `/` operator) that will never\ncrash the app. If the `y` argument in `safeDivide x y` is zero, we return `Nothing`.\n\n safeDivide 5 2 --> Just 2.5\n\n -- the interesting part\n safeDivide 5 0 --> Nothing\n\n","type":"Basics.Float -> Basics.Float -> Maybe.Maybe Basics.Float"},{"name":"safeIntegerDivide","comment":" Perform integer division (like Elm's `//` operator) that will never crash\nthe app. If the `y` argument in `safeIntegerDivide x y` is zero, we return `Nothing`.\n\n safeIntegerDivide 5 2 --> Just 2\n\n -- the interesting part\n safeIntegerDivide 5 0 --> Nothing\n\n","type":"Basics.Int -> Basics.Int -> Maybe.Maybe Basics.Int"},{"name":"safeModBy","comment":" Perform [modular arithmetic][ma] that will never crash the app. If the `modulus`\nargument in `safeModBy modulus x` is zero, we return `Nothing`.\n\n safeModBy 2 4 --> Just 0\n\n safeModBy 2 5 --> Just 1\n\n -- the interesting part\n safeModBy 0 4 --> Nothing\n\nUse [`safeRemainderBy`](#safeRemainderBy) for a different treatment of negative\nnumbers, or read Daan Leijen’s [Division and Modulus for Computer Scientists][dm]\nfor more information.\n\n[ma]: https://en.wikipedia.org/wiki/Modular_arithmetic\n[dm]: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf\n\n","type":"Basics.Int -> Basics.Int -> Maybe.Maybe Basics.Int"},{"name":"safeRemainderBy","comment":" Get the remainder after division in a way that will never crash the app. If\nthe `divisor` argument in `safeRemainderBy divisor x` is zero, we return `Nothing`.\n\n safeRemainderBy 2 4 --> Just 0\n\n safeRemainderBy 2 5 --> Just 1\n\n -- the interesting part\n safeRemainderBy 0 4 --> Nothing\n\nUse [`safeModBy`](#safeModBy) for a different treatment of negative\nnumbers, or read Daan Leijen’s [Division and Modulus for Computer Scientists][dm]\nfor more information.\n\n[dm]: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf\n\n","type":"Basics.Int -> Basics.Int -> Maybe.Maybe Basics.Int"},{"name":"swap","comment":" Swaps the elements in a pair.\n\n swap ( 1, 2 ) --> ( 2, 1 )\n\n","type":"( a, b ) -> ( b, a )"},{"name":"toOrder","comment":" Helper for multi-dimensional sort.\n\nTakes a function that extracts a comparable value from a type `a` as a key,\nand returns a function `a -> a -> Order`.\n\nThis is primarily a helper function for the `orderBy` function above.\n\n {- Simple example: wrapping a function that turns\n a custom type into an instance of `comparable`\n -}\n\n type Color\n = Red\n | Yellow\n | Green\n\n colorToComparable : Color -> Int\n colorToComparable light =\n case light of\n Red -> 0\n Yellow -> 1\n Green -> 2\n\n colorToOrder : Color -> Color -> Order\n colorToOrder =\n toOrder colorToComparable\n\n List.sortWith\n colorToOrder\n [ Yellow, Yellow, Red, Green, Red ]\n --> [ Red, Red, Yellow, Yellow, Green ]\n\n\n {- More interesting example: using the property accessor\n methods on a custom type with `toOrder`; we only need\n this function when we want to combine multiple ordering functions into one.\n -}\n\n type alias Light =\n { color : Color\n , action : String\n , timeActivatedSeconds : Float\n }\n\n lights : List Light\n lights =\n [ Light Green \"Go\" 60\n , Light Yellow \"Slow down\" 5.5\n , Light Red \"Stop\" 60\n ]\n\n List.sortWith\n ( orderBy\n [ toOrder .timeActivatedSeconds\n , toOrder (.color >> colorToComparable)\n ]\n )\n lights\n --> [ Light Yellow \"Slow down\" 5.5\n --> , Light Red \"Stop\" 60\n --> , Light Green \"Go\" 60\n --> ]\n\n(Note that `List.sortWith colorOrder` above is identical to `List.sortBy colorToComparable`.)\n\n","type":"(a -> comparable) -> a -> a -> Basics.Order"},{"name":"toOrderDesc","comment":" Same as `toOrder`, with flipped comparisons to enable \"sort by descending\".\n\n type Color\n = Red\n | Yellow\n | Green\n\n colorToComparable : Color -> Int\n colorToComparable light =\n case light of\n Red -> 0\n Yellow -> 1\n Green -> 2\n\n colorToOrder : Color -> Color -> Order\n colorToOrder =\n toOrderDesc colorToComparable\n\n List.sortWith\n colorToOrder\n [ Yellow, Yellow, Red, Green, Red ]\n --> [ Green, Yellow, Yellow, Red, Red ]\n\n","type":"(a -> comparable) -> a -> a -> Basics.Order"},{"name":"uncurry","comment":" Change how arguments are passed to a function.\nThis combines two arguments into a single pair.\n","type":"(a -> b -> c) -> ( a, b ) -> c"}],"binops":[]},{"name":"Char.Extra","comment":" Convenience functionality on [`Char`](https://package.elm-lang.org/packages/elm/core/latest/Char)\n\n@docs isSpace, isControl\n\n","unions":[],"aliases":[],"values":[{"name":"isControl","comment":" Returns true if the given character is an ASCII control character.\n","type":"Char.Char -> Basics.Bool"},{"name":"isSpace","comment":" Returns true if the given character is whitespace character.\n","type":"Char.Char -> Basics.Bool"}],"binops":[]},{"name":"Cmd.Extra","comment":" Extra functions for working with Cmds.\n\n\n# Constructors\n\n@docs perform, attempt, maybe, fromResult, fromMaybe\n\n\n# Chaining in update\n\n@docs pure, with, add, withTrigger, addTrigger, addIf, addTriggerMaybe, addMaybe\n\n","unions":[],"aliases":[],"values":[{"name":"add","comment":" Add new cmd to an existing pair.\n","type":"Platform.Cmd.Cmd msg -> ( model, Platform.Cmd.Cmd msg ) -> ( model, Platform.Cmd.Cmd msg )"},{"name":"addIf","comment":" Add new cmd to an existing pair under a certain condition.\n\n prevCmd : Cmd String\n prevCmd =\n perform \"foo\"\n\n newCmd : Cmd String\n newCmd =\n perform \"bar\"\n\n ( \"model\", prevCmd )\n |> addIf False newCmd\n |> Tuple.second\n |> ((==) prevCmd)\n --> True\n\n","type":"Basics.Bool -> Platform.Cmd.Cmd msg -> ( model, Platform.Cmd.Cmd msg ) -> ( model, Platform.Cmd.Cmd msg )"},{"name":"addMaybe","comment":" Add new cmd to an existing pair based on the Maybe value\n\n prevCmd : Cmd String\n prevCmd =\n perform \"prev\"\n\n ( \"model\", prevCmd )\n |> addMaybe identity Nothing\n |> Tuple.second\n |> ((==) prevCmd)\n --> True\n\n","type":"(a -> Platform.Cmd.Cmd msg) -> Maybe.Maybe a -> ( model, Platform.Cmd.Cmd msg ) -> ( model, Platform.Cmd.Cmd msg )"},{"name":"addTrigger","comment":" Add new trigger of Msg to an existing pair.\n","type":"msg -> ( model, Platform.Cmd.Cmd msg ) -> ( model, Platform.Cmd.Cmd msg )"},{"name":"addTriggerMaybe","comment":" `addTrigger` if Just, do nothing if Nothing\n","type":"Maybe.Maybe msg -> ( model, Platform.Cmd.Cmd msg ) -> ( model, Platform.Cmd.Cmd msg )"},{"name":"attempt","comment":" Similar to perform but takes `Result msg` and performs action only on `Ok`.\n\n attempted : Cmd String\n attempted =\n attempt <| Ok \"I'm fine\"\n\n attempt (Err \"Failed\") == Cmd.none\n --> True\n\n","type":"Result.Result x msg -> Platform.Cmd.Cmd msg"},{"name":"fromMaybe","comment":" Construct from Maybe.\n\n maybeCmd : Cmd (Maybe Int)\n maybeCmd =\n identity (Just 1)\n\n fromMaybe identity Nothing\n --> Cmd.none\n\n","type":"(a -> msg) -> Maybe.Maybe a -> Platform.Cmd.Cmd msg"},{"name":"fromResult","comment":" Construct from Result.\n\n resultCmd : Cmd (Result Never Int)\n resultCmd =\n fromResult identity (Ok 1)\n\n fromResult identity (Err ())\n --> Cmd.none\n\n","type":"(a -> msg) -> Result.Result x a -> Platform.Cmd.Cmd msg"},{"name":"maybe","comment":" Similar to attempt but works with `Maybe` instead\n\n maybeCmd : Cmd Int\n maybeCmd =\n maybe <| Just 1\n\n maybe Nothing == Cmd.none\n --> True\n\n","type":"Maybe.Maybe msg -> Platform.Cmd.Cmd msg"},{"name":"perform","comment":" Cmd costructor.\nUseful when you want to artificially emit Cmd from update function.\n\n performed : Cmd String\n performed =\n perform \"foo\"\n\n\"real world\" example:\n\n type alias Model =\n ()\n\n type Msg\n = Fire\n | FireRockets\n\n update : Msg -> Model -> ( Model, Cmd Msg )\n update msg () =\n case msg of\n Fire ->\n ( (), perform FireRockets )\n\n FireRockets ->\n Debug.crash \"World ended:(\"\n\n","type":"msg -> Platform.Cmd.Cmd msg"},{"name":"pure","comment":" Creates pair `model` with `Cmd.none`\n\n pair : ( String, Cmd msg )\n pair = pure \"foo\"\n\n pair\n |> Tuple.second\n |> ((==) Cmd.none)\n --> True\n\n","type":"model -> ( model, Platform.Cmd.Cmd msg )"},{"name":"with","comment":" Add Cmd to model to create a pair.\n","type":"Platform.Cmd.Cmd msg -> model -> ( model, Platform.Cmd.Cmd msg )"},{"name":"withTrigger","comment":" Trigger Cmd from Msg and create a pair\n","type":"msg -> model -> ( model, Platform.Cmd.Cmd msg )"}],"binops":[]},{"name":"Dict.Extra","comment":" Convenience functions for working with `Dict`\n\n\n# List operations\n\n@docs groupBy, filterGroupBy, fromListBy, fromListDedupe, fromListDedupeBy, frequencies\n\n\n# Manipulation\n\n@docs removeWhen, removeMany, keepOnly, insertDedupe, mapKeys, filterMap, invert\n\n\n# Utilities\n\n@docs any, find\n\n","unions":[],"aliases":[],"values":[{"name":"any","comment":" Determine if any key/value pair satisfies some test.\n\n import Dict\n\n Dict.fromList [ ( 9, \"Jill\" ), ( 7, \"Jill\" ) ]\n |> any (\\_ value -> value == \"Jill\")\n --> True\n\n Dict.fromList [ ( 9, \"Jill\" ), ( 7, \"Jill\" ) ]\n |> any (\\key _ -> key == 5)\n --> False\n\n","type":"(comparable -> a -> Basics.Bool) -> Dict.Dict comparable a -> Basics.Bool"},{"name":"filterGroupBy","comment":" Takes a key-fn and a list.\nCreates a `Dict` which maps the key to a list of matching elements, skipping elements\nwhere key-fn returns `Nothing`\n\n import Dict\n\n filterGroupBy (String.uncons >> Maybe.map Tuple.first) [ \"tree\" , \"\", \"tweet\", \"apple\" , \"leaf\", \"\" ]\n --> Dict.fromList [ ( 't', [ \"tree\", \"tweet\" ] ), ( 'a', [ \"apple\" ] ), ( 'l', [ \"leaf\" ] ) ]\n\n filterGroupBy\n .car\n [ { name = \"Mary\"\n , car = Just \"Ford\"\n }\n , { name = \"Jack\"\n , car = Nothing\n }\n , { name = \"Jill\"\n , car = Just \"Tesla\"\n }\n , { name = \"John\"\n , car = Just \"Tesla\"\n }\n ]\n --> Dict.fromList\n --> [ ( \"Ford\"\n --> , [ { name = \"Mary\" , car = Just \"Ford\" } ]\n --> )\n --> , ( \"Tesla\"\n --> , [ { name = \"Jill\" , car = Just \"Tesla\" }\n --> , { name = \"John\" , car = Just \"Tesla\" }\n --> ]\n --> )\n --> ]\n\n","type":"(a -> Maybe.Maybe comparable) -> List.List a -> Dict.Dict comparable (List.List a)"},{"name":"filterMap","comment":" Apply a function that may or may not succeed to all entries in a dictionary,\nbut only keep the successes.\n\n import Dict\n\n let\n isTeen n a =\n if 13 <= n && n <= 19 then\n Just <| String.toUpper a\n else\n Nothing\n in\n Dict.fromList [ ( 5, \"Jack\" ), ( 15, \"Jill\" ), ( 20, \"Jones\" ) ]\n |> filterMap isTeen\n --> Dict.fromList [ ( 15, \"JILL\" ) ]\n\n","type":"(comparable -> a -> Maybe.Maybe b) -> Dict.Dict comparable a -> Dict.Dict comparable b"},{"name":"find","comment":" Find the first key/value pair that matches a predicate.\n\n import Dict\n\n Dict.fromList [ ( 9, \"Jill\" ), ( 7, \"Jill\" ) ]\n |> find (\\_ value -> value == \"Jill\")\n --> Just ( 7, \"Jill\" )\n\n Dict.fromList [ ( 9, \"Jill\" ), ( 7, \"Jill\" ) ]\n |> find (\\key _ -> key == 5)\n --> Nothing\n\n","type":"(comparable -> a -> Basics.Bool) -> Dict.Dict comparable a -> Maybe.Maybe ( comparable, a )"},{"name":"frequencies","comment":" Count the number of occurences for each of the elements in the list.\n\n import Dict\n\n frequencies [ \"A\", \"B\", \"C\", \"B\", \"C\", \"B\" ]\n --> Dict.fromList [ ( \"A\", 1 ), ( \"B\", 3 ), ( \"C\", 2 ) ]\n\n","type":"List.List comparable -> Dict.Dict comparable Basics.Int"},{"name":"fromListBy","comment":" Create a dictionary from a list of values, by passing a function that can get a key from any such value.\nIf the function does not return unique keys, earlier values are discarded.\n\n import Dict\n\n fromListBy String.length [ \"tree\" , \"apple\" , \"leaf\" ]\n --> Dict.fromList [ ( 4, \"leaf\" ), ( 5, \"apple\" ) ]\n\n","type":"(a -> comparable) -> List.List a -> Dict.Dict comparable a"},{"name":"fromListDedupe","comment":" Like `Dict.fromList`, but you provide a way to deal with\nduplicate keys. Create a dictionary from a list of pairs of keys and\nvalues, providing a function that is used to combine multiple values\npaired with the same key.\n\n import Dict\n\n fromListDedupe\n (\\a b -> a ++ \" \" ++ b)\n [ ( \"class\", \"menu\" ), ( \"width\", \"100%\" ), ( \"class\", \"big\" ) ]\n --> Dict.fromList [ ( \"class\", \"menu big\" ), ( \"width\", \"100%\" ) ]\n\n","type":"(a -> a -> a) -> List.List ( comparable, a ) -> Dict.Dict comparable a"},{"name":"fromListDedupeBy","comment":" `fromListBy` and `fromListDedupe` rolled into one.\n\n import Dict\n\n fromListDedupeBy (\\first second -> first) String.length [ \"tree\" , \"apple\" , \"leaf\" ]\n --> Dict.fromList [ ( 4, \"tree\" ), ( 5, \"apple\" ) ]\n\n","type":"(a -> a -> a) -> (a -> comparable) -> List.List a -> Dict.Dict comparable a"},{"name":"groupBy","comment":" Takes a key-fn and a list.\nCreates a `Dict` which maps the key to a list of matching elements.\n\n import Dict\n\n groupBy String.length [ \"tree\" , \"apple\" , \"leaf\" ]\n --> Dict.fromList [ ( 4, [ \"tree\", \"leaf\" ] ), ( 5, [ \"apple\" ] ) ]\n\n","type":"(a -> comparable) -> List.List a -> Dict.Dict comparable (List.List a)"},{"name":"insertDedupe","comment":" Insert an element at the given key, providing a combining\nfunction that used in the case that there is already an\nelement at that key. The combining function is called with\noriginal element and the new element as arguments and\nreturns the element to be inserted.\n\n import Dict\n\n Dict.fromList [ ( \"expenses\", 38.25 ), ( \"assets\", 100.85 ) ]\n |> insertDedupe (+) \"expenses\" 2.50\n |> insertDedupe (+) \"liabilities\" -2.50\n --> Dict.fromList [ ( \"expenses\", 40.75 ), ( \"assets\", 100.85 ), ( \"liabilities\", -2.50 ) ]\n\n","type":"(v -> v -> v) -> comparable -> v -> Dict.Dict comparable v -> Dict.Dict comparable v"},{"name":"invert","comment":" Inverts the keys and values of an array.\n\n import Dict\n\n Dict.fromList [ (\"key\", \"value\") ]\n |> invert\n --> Dict.fromList [ ( \"value\", \"key\" ) ]\n\n","type":"Dict.Dict comparable1 comparable2 -> Dict.Dict comparable2 comparable1"},{"name":"keepOnly","comment":" Keep a key-value pair if its key appears in the set.\n\n import Dict\n import Set\n\n Dict.fromList [ ( \"Mary\", 1 ), ( \"Jack\", 2 ), ( \"Jill\", 1 ) ]\n |> keepOnly (Set.fromList [ \"Jack\", \"Jill\" ])\n --> Dict.fromList [ ( \"Jack\", 2 ), ( \"Jill\", 1 ) ]\n\n","type":"Set.Set comparable -> Dict.Dict comparable v -> Dict.Dict comparable v"},{"name":"mapKeys","comment":" Apply a function to all keys in a dictionary.\n\n import Dict\n\n Dict.fromList [ ( 5, \"Jack\" ), ( 10, \"Jill\" ) ]\n |> mapKeys (\\x -> x + 1)\n --> Dict.fromList [ ( 6, \"Jack\" ), ( 11, \"Jill\" ) ]\n\n Dict.fromList [ ( 5, \"Jack\" ), ( 10, \"Jill\" ) ]\n |> mapKeys String.fromInt\n --> Dict.fromList [ ( \"5\", \"Jack\" ), ( \"10\", \"Jill\" ) ]\n\n","type":"(comparable -> comparable1) -> Dict.Dict comparable v -> Dict.Dict comparable1 v"},{"name":"removeMany","comment":" Remove a key-value pair if its key appears in the set.\n\n import Dict\n import Set\n\n Dict.fromList [ ( \"Mary\", 1 ), ( \"Jack\", 2 ), ( \"Jill\", 1 ) ]\n |> removeMany (Set.fromList [ \"Mary\", \"Jill\" ])\n --> Dict.fromList [ ( \"Jack\", 2 ) ]\n\n","type":"Set.Set comparable -> Dict.Dict comparable v -> Dict.Dict comparable v"},{"name":"removeWhen","comment":" Remove elements which satisfies the predicate.\n\n import Dict\n\n Dict.fromList [ ( \"Mary\", 1 ), ( \"Jack\", 2 ), ( \"Jill\", 1 ) ]\n |> removeWhen (\\_ value -> value == 1 )\n --> Dict.fromList [ ( \"Jack\", 2 ) ]\n\n","type":"(comparable -> v -> Basics.Bool) -> Dict.Dict comparable v -> Dict.Dict comparable v"}],"binops":[]},{"name":"Float.Extra","comment":"\n\n\n# Equality\n\n@docs aboutEqual\n\n\n# Formatting Floats\n\n@docs toFixedDecimalPlaces, toFixedSignificantDigits, boundaryValuesAsUnicode\n\n\n# Ranges\n\n@docs range\n\n","unions":[],"aliases":[],"values":[{"name":"aboutEqual","comment":" Comparing Floats with `==` is usually wrong, unless you basically care for reference equality, since floating point\nnumbers often have small precision drift.\n\n 0.1 + 0.2 == 0.3 --> False\n\nThis function implements an approximation where we are asking - are these values close enough that we can consider their difference to be\ndue to floating point drift rather than a result of meaningful difference in calculation?\n\n (0.1 + 0.2) |> Float.Extra.aboutEqual 0.3 --> True\n\nNote: this is unlikely to be appropriate if you are performing computations much smaller than one.\n\n (0.00001 + 0.00002) |> Float.Extra.aboutEqual 0.00003 --> True\n\nThis value handles Infinity and NaN like so:\n\n (1 / 0) |> Float.Extra.aboutEqual (100 / 0) --> True\n\n (0 / 0) |> Float.Extra.aboutEqual (0 / 0) --> False\n\n","type":"Basics.Float -> Basics.Float -> Basics.Bool"},{"name":"boundaryValuesAsUnicode","comment":" When showing Float values to users, we generally don't particularly want them to see programmer-y values like\n`NaN` or `Infinity`. This function wraps a number formatting routine, but replaces those values with unicode symbols:\n\n format : Float -> String\n format =\n Float.Extra.toFixedSignificantDigits 3\n |> Float.Extra.boundaryValuesAsUnicode\n\n format (0 / 0) --> \"∅\"\n format (1 / 0) --> \"∞\"\n format (-1 / 0) --> \"-∞\"\n format (1 / 3) -> \"0.333\"\n\nOf course using this is unsuitable for when you want the numbers to be machine readable.\n\n","type":"(Basics.Float -> String.String) -> Basics.Float -> String.String"},{"name":"range","comment":" Returns a List containing an arithmetic progression, similar to the Python\nbuilt-in range.\n\nTakes a `start`, `stop` and `step` argument. The stop value is exclusive; it is not\nincluded in the result. If `step` is positive, the last element is the largest\n`start + i * step` less than `stop`; if `step` is negative, the last element is\nthe smallest `start + i * step` greater than `stop`. If the returned list would\ncontain an infinite number of values, an empty range is returned.\n\nThe arguments are not required to be whole numbers; however, the results are more\npredictable if they are.\n\nDifferences from [List.range from the standard library](https://package.elm-lang.org/packages/elm/core/latest/List#range):\n\n - `List.range` is inclusive, meaning that the stop value will be included in the result\n - `List.range` supports `Int`, whereas this uses `Float`\n - `List.range` supports only increasing intervals (i.e. `List.range 3 1 == []` vs. `range 3 1 -1 == [3, 2]`)\n - `List.range` doesn't allow for specifying the step value\n\n","type":"Basics.Float -> Basics.Float -> Basics.Float -> List.List Basics.Float"},{"name":"toFixedDecimalPlaces","comment":" Fix a float value represented to a certain number of decimal places as a string.\n\n Float.Extra.toFixedDecimalPlaces 3 0.0326232 --> \"0.033\"\n\n","type":"Basics.Int -> Basics.Float -> String.String"},{"name":"toFixedSignificantDigits","comment":" Fix a float value represented as a string to a certain number of significant digits.\n\n Float.Extra.toFixedSignificantDigits 2 1.435 --> \"1.4\"\n\n Float.Extra.toFixedSignificantDigits 2 545435 --> \"550000\"\n\n Float.Extra.toFixedSignificantDigits 2 0.0039 --> \"0.0039\"\n\n","type":"Basics.Int -> Basics.Float -> String.String"}],"binops":[]},{"name":"List.Extra","comment":" Convenience functions for working with List\n\n\n# Basics\n\n@docs last, init, getAt, uncons, unconsLast, maximumBy, maximumWith, minimumBy, minimumWith, andMap, andThen, reverseMap, reverseFilter, takeWhile, dropWhile, unique, uniqueBy, allDifferent, allDifferentBy, setIf, setAt, remove, updateIf, updateAt, updateIfIndex, removeAt, removeIfIndex, filterNot, swapAt, stableSortWith\n\n\n# List transformations\n\n@docs intercalate, transpose, subsequences, permutations, interweave, cartesianProduct, uniquePairs\n\n\n# Folds\n\n@docs foldl1, foldr1, indexedFoldl, indexedFoldr, Step, stoppableFoldl\n\n\n# Building lists\n\n@docs scanl, scanl1, scanr, scanr1, mapAccuml, mapAccumr, unfoldr, iterate, initialize, cycle, reverseRange\n\n\n# Sublists\n\n@docs splitAt, splitWhen, takeWhileRight, dropWhileRight, span, break, stripPrefix, group, groupWhile, inits, tails, select, selectSplit, gatherEquals, gatherEqualsBy, gatherWith, subsequencesNonEmpty, frequencies\n\n\n# Predicates\n\n@docs isPrefixOf, isSuffixOf, isInfixOf, isSubsequenceOf, isPermutationOf\n\n\n# Searching\n\n@docs notMember, find, elemIndex, elemIndices, findIndex, findIndices, findMap, count\n\n\n# Zipping\n\n@docs zip, zip3\n\n\n# Lift functions onto multiple lists of arguments\n\n@docs lift2, lift3, lift4\n\n\n# Split to groups of given size\n\n@docs groupsOf, groupsOfWithStep, groupsOfVarying, greedyGroupsOf, greedyGroupsOfWithStep\n\n\n# Joins\n\n@docs joinOn\n\n","unions":[{"name":"Step","comment":" A custom type used for stoppable folds.\n","args":["a"],"cases":[["Continue",["a"]],["Stop",["a"]]]}],"aliases":[],"values":[{"name":"allDifferent","comment":" Indicate if list has duplicate values.\n\n allDifferent [ 0, 1, 1, 0, 1 ]\n --> False\n\n allDifferent [ 0, 1, 2]\n --> True\n\n","type":"List.List a -> Basics.Bool"},{"name":"allDifferentBy","comment":" Indicate if list has duplicate values when supplied function are applied on each values.\n","type":"(a -> b) -> List.List a -> Basics.Bool"},{"name":"andMap","comment":" Map functions taking multiple arguments over multiple lists. Each list should be of the same length.\n\n toIntFunctions : List (Float -> Int)\n toIntFunctions =\n [ round\n , floor\n , ceiling\n , truncate\n ]\n\n toIntFunctions\n |> andMap [ -1.5, -1.5, -1.5, -1.5 ]\n --> [ -1, -2, -1, -1 ]\n\n\n math : List (Int -> Int)\n math =\n [ (+) 1\n , (*) 2\n , (*) 3 >> (+) 1\n ]\n\n math\n |> andMap [ 1, 2, 3 ]\n --> [ 2, 4, 10 ]\n\n","type":"List.List a -> List.List (a -> b) -> List.List b"},{"name":"andThen","comment":" Equivalent to `concatMap`. For example, suppose you want to have a cartesian product of [1,2] and [3,4]:\n\n [ 1, 2 ]\n |> andThen\n (\\x ->\n [ 3, 4 ]\n |> andThen (\\y -> [ ( x, y ) ])\n )\n --> [ ( 1, 3 ), ( 1, 4 ), ( 2, 3 ), ( 2, 4 ) ]\n\nNow suppose we want to have a cartesian product between the first list and the second list and its doubles:\n\n [ 1, 2 ]\n |> andThen\n (\\x ->\n [ 3, 4 ]\n |> andThen\n (\\y ->\n [ y, y * 2 ]\n |> andThen (\\z -> [ ( x, z ) ])\n )\n )\n --> [ ( 1, 3 ), ( 1, 6 ), ( 1, 4 ), ( 1, 8 ), ( 2, 3 ), ( 2, 6 ), ( 2, 4 ), ( 2, 8 )]\n\nAdvanced functional programmers will recognize this as the implementation of bind operator (>>=) for lists from the `Monad` typeclass.\n\n","type":"(a -> List.List b) -> List.List a -> List.List b"},{"name":"break","comment":" Take a predicate and a list, return a tuple. The first part of the tuple is the longest prefix of that list, for each element of which the predicate _does not_ hold. The second part of the tuple is the remainder of the list. `break p xs` is equivalent to `(takeWhile (not p) xs, dropWhile (not p) xs)`.\n\n break ((<) 3) [ 1, 2, 3, 4, 1, 2, 3, 4 ]\n --> ( [ 1, 2, 3 ], [ 4, 1, 2, 3, 4 ] )\n\n break ((>) 5) [ 1, 2, 3 ]\n --> ( [], [ 1, 2, 3 ] )\n\n break ((<) 5) [ 1, 2, 3 ]\n --> ( [ 1, 2, 3 ], [] )\n\n","type":"(a -> Basics.Bool) -> List.List a -> ( List.List a, List.List a )"},{"name":"cartesianProduct","comment":" Return the cartesian product of a list of lists.\nIf one list is empty, the result is an empty list.\nIf the list of lists is empty, the result is an empty singleton.\n\n cartesianProduct [ [ 1, 2 ], [ 3, 4, 5 ], [ 6 ] ]\n --> [ [ 1, 3, 6 ], [ 1, 4, 6 ], [ 1, 5, 6 ], [ 2, 3, 6 ], [ 2, 4, 6 ], [ 2, 5, 6 ] ]\n\n cartesianProduct [ [ 1, 2 ] ]\n --> [ [ 1 ], [ 2 ] ]\n\n cartesianProduct [ [ 1, 2 ], [], [ 6 ] ]\n --> []\n\n cartesianProduct [ [] ]\n --> []\n\n cartesianProduct []\n --> [ [] ]\n\n","type":"List.List (List.List a) -> List.List (List.List a)"},{"name":"count","comment":" Returns the number of elements in a list that satisfy a given predicate.\nEquivalent to `List.length (List.filter pred list)` but more efficient.\n\n count\n (modBy 2 >> (==) 1) [ 1, 2, 3, 4, 5, 6, 7 ]\n --> 4\n\n count\n ((==) \"yeah\")\n [ \"She\", \"loves\", \"you\", \"yeah\", \"yeah\", \"yeah\" ]\n --> 3\n\n","type":"(a -> Basics.Bool) -> List.List a -> Basics.Int"},{"name":"cycle","comment":" Creates a list of the given length whose elements are obtained by cycling\nthrough the elements of the given list. If the given list is empty, the\nresulting list will be empty.\n\n cycle 6 [ 4, 7, 8 ]\n --> [ 4, 7, 8, 4, 7, 8 ]\n\n cycle 4 [ 'a', 'b', 'c' ]\n --> [ 'a', 'b', 'c', 'a' ]\n\n cycle 9001 []\n --> []\n\n cycle 2 [ 1, 2, 3, 4, 5 ]\n --> [ 1, 2 ]\n\n","type":"Basics.Int -> List.List a -> List.List a"},{"name":"dropWhile","comment":" Drop elements in order as long as the predicate evaluates to `True`\n","type":"(a -> Basics.Bool) -> List.List a -> List.List a"},{"name":"dropWhileRight","comment":" Drop elements from the right, while predicate still holds.\n\n dropWhileRight ((<) 5) (List.range 1 10)\n --> [ 1, 2, 3, 4, 5 ]\n\n","type":"(a -> Basics.Bool) -> List.List a -> List.List a"},{"name":"elemIndex","comment":" Return the index of the first occurrence of the element. Otherwise, return `Nothing`. Indexing starts from 0.\n\n elemIndex 1 [ 1, 2, 3 ]\n --> Just 0\n\n elemIndex 4 [ 1, 2, 3 ]\n --> Nothing\n\n elemIndex 1 [ 1, 2, 1 ]\n --> Just 0\n\n","type":"a -> List.List a -> Maybe.Maybe Basics.Int"},{"name":"elemIndices","comment":" Return all indices of occurrences of the element. If element is not found, return empty list. Indexing starts from 0.\n\n elemIndices 1 [ 1, 2, 3 ]\n --> [ 0 ]\n\n elemIndices 4 [ 1, 2, 3 ]\n --> []\n\n elemIndices 1 [ 1, 2, 1 ]\n --> [ 0, 2 ]\n\n","type":"a -> List.List a -> List.List Basics.Int"},{"name":"filterNot","comment":" Take a predicate and a list, and return a list that contains elements which fails to satisfy the predicate.\nThis is equivalent to `List.filter (not << predicate) list`.\n\n isEven : Int -> Bool\n isEven i =\n modBy 2 i == 0\n\n filterNot isEven [ 1, 2, 3, 4 ]\n --> [ 1, 3 ]\n\n","type":"(a -> Basics.Bool) -> List.List a -> List.List a"},{"name":"find","comment":" Find the first element that satisfies a predicate and return\nJust that element. If none match, return Nothing.\n\n find (\\num -> num > 5) [ 2, 4, 6, 8 ]\n --> Just 6\n\n","type":"(a -> Basics.Bool) -> List.List a -> Maybe.Maybe a"},{"name":"findIndex","comment":" Take a predicate and a list, return the index of the first element that satisfies the predicate. Otherwise, return `Nothing`. Indexing starts from 0.\n\n isEven : Int -> Bool\n isEven i =\n modBy 2 i == 0\n\n findIndex isEven [ 1, 2, 3 ]\n --> Just 1\n\n findIndex isEven [ 1, 3, 5 ]\n --> Nothing\n\n findIndex isEven [ 1, 2, 4 ]\n --> Just 1\n\n","type":"(a -> Basics.Bool) -> List.List a -> Maybe.Maybe Basics.Int"},{"name":"findIndices","comment":" Take a predicate and a list, return indices of all elements satisfying the predicate. Otherwise, return empty list. Indexing starts from 0.\n\n isEven : Int -> Bool\n isEven i =\n modBy 2 i == 0\n\n findIndices isEven [ 1, 2, 3 ]\n --> [ 1 ]\n\n findIndices isEven [ 1, 3, 5 ]\n --> []\n\n findIndices isEven [ 1, 2, 4 ]\n --> [ 1, 2 ]\n\n","type":"(a -> Basics.Bool) -> List.List a -> List.List Basics.Int"},{"name":"findMap","comment":" Apply a function that may succeed to values in the list and return the result of the first successful match. If none match, then return Nothing.\n\n mapOverFive : Int -> Maybe Int\n mapOverFive num =\n if num > 5 then\n Just (num * 2)\n else\n Nothing\n\n findMap mapOverFive [2, 4, 6, 8]\n --> Just 12\n\nThis is particularly useful in cases where you have a complex type in a list, and you need to pick out the the first one\n\n type alias HouseModel =\n {}\n\n type Property\n = Rental\n | House HouseModel\n | Commercial\n\n toHouse : Property -> Maybe HouseModel\n toHouse property =\n case property of\n House house ->\n Just house\n\n _ ->\n Nothing\n\n viewFirstHomeOfInterest : Viewer -> List Property -> Html msg\n viewFirstHomeOfInterest viewer propertiesQuery =\n propertiesQuery\n |> findMap toHouse\n |> Maybe.map homeView\n |> Maybe.withDefault noHomeView\n\n","type":"(a -> Maybe.Maybe b) -> List.List a -> Maybe.Maybe b"},{"name":"foldl1","comment":" Variant of `foldl` that has no starting value argument and treats the head of the list as its starting value. If the list is empty, return `Nothing`.\n\n foldl1 (-) [ 1, 2, 3, 4 ]\n --> Just 2\n\n foldl1 (++) [ \"a\", \"b\", \"c\" ]\n --> Just \"cba\"\n\n foldl1 min []\n --> Nothing\n\n**Note:** This function changed in a major way between version 7.0.0 and 8.0.0 of this package. The function `foldl1` took in 7.0.0 was `b -> a -> b` consistent with the Haskell implementation of `foldl`, but now its `a -> b -> b`, consistent with `List.foldl`. This function behaves differently in a breaking way, even though its type signature is the same.\n\n","type":"(a -> a -> a) -> List.List a -> Maybe.Maybe a"},{"name":"foldr1","comment":" Variant of `foldr` that has no starting value argument and treats the last element of the list as its starting value. If the list is empty, return `Nothing`.\n\n foldr1 (-) [ 1, 2, 3, 4 ]\n --> Just -2\n\n foldr1 (++) [ \"a\", \"b\", \"c\" ]\n --> Just \"abc\"\n\n foldr1 min []\n --> Nothing\n\n","type":"(a -> a -> a) -> List.List a -> Maybe.Maybe a"},{"name":"frequencies","comment":" Calculate the number of occurences for each element in a list. Elements\nwill be ordered ascendingly, then grouped in a tuple with the number of\noccurences.\n\n frequencies [2,1,3,2,3,3]\n --> [(1,1),(2,2),(3,3)]\n\n","type":"List.List comparable -> List.List ( comparable, Basics.Int )"},{"name":"gatherEquals","comment":" Group equal elements together. This is different from `group` as each sublist\nwill contain _all_ equal elements of the original list. Elements will be grouped\nin the same order as they appear in the original list. The same applies to elements\nwithin each group.\n\n gatherEquals [1,2,1,3,2]\n --> [(1,[1]),(2,[2]),(3,[])]\n\n","type":"List.List a -> List.List ( a, List.List a )"},{"name":"gatherEqualsBy","comment":" Group equal elements together. A function is applied to each element of the list\nand then the equality check is performed against the results of that function evaluation.\nElements will be grouped in the same order as they appear in the original list. The\nsame applies to elements within each group.\n\n gatherEqualsBy .age [{age=25},{age=23},{age=25}]\n --> [({age=25},[{age=25}]),({age=23},[])]\n\n","type":"(a -> b) -> List.List a -> List.List ( a, List.List a )"},{"name":"gatherWith","comment":" Group equal elements together using a custom equality function. Elements will be\ngrouped in the same order as they appear in the original list. The same applies to\nelements within each group.\n\n gatherWith (==) [1,2,1,3,2]\n --> [(1,[1]),(2,[2]),(3,[])]\n\n","type":"(a -> a -> Basics.Bool) -> List.List a -> List.List ( a, List.List a )"},{"name":"getAt","comment":" Returns `Just` the element at the given index in the list,\nor `Nothing` if the index is out of range.\n","type":"Basics.Int -> List.List a -> Maybe.Maybe a"},{"name":"greedyGroupsOf","comment":" Greedily split list into groups of length `size`. The last group of\nelements will be included regardless of whether there are enough elements in\nthe list to completely fill it. This is equivalent to calling\n`greedyGroupsOfWithStep` with the same `size` and `step`.\n\n greedyGroupsOf 3 (List.range 1 10)\n --> [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ], [ 10 ] ]\n\n","type":"Basics.Int -> List.List a -> List.List (List.List a)"},{"name":"greedyGroupsOfWithStep","comment":" Greedily split list into groups of length `size` at offsets `step` apart.\nThe last group of elements will be included regardless of whether there are\nenough elements in the list to completely fill it. (See `groupsOfWithStep`\nfor the non-greedy version of this function).\n\n greedyGroupsOfWithStep 4 4 (List.range 1 10)\n --> [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9, 10 ] ]\n\n greedyGroupsOfWithStep 3 2 (List.range 1 6)\n --> [ [ 1, 2, 3 ], [ 3, 4, 5 ], [ 5, 6 ] ]\n\n greedyGroupsOfWithStep 3 6 (List.range 1 20)\n --> [ [ 1, 2, 3 ], [ 7, 8, 9 ], [ 13, 14, 15 ], [ 19, 20 ] ]\n\nIf `step == size`, every element will appear in exactly one group. If\n`step < size`, there will be an overlap between groups. If `step > size`, some\nelements will be skipped and not appear in any groups.\n\n","type":"Basics.Int -> Basics.Int -> List.List a -> List.List (List.List a)"},{"name":"group","comment":" Group similar elements together. `group` is equivalent to `groupWhile (==)`.\n\n group [ 1, 2, 2, 3, 3, 3, 2, 2, 1 ]\n --> [ (1, []), (2, [ 2 ]), (3, [ 3, 3 ]), (2, [ 2 ]), ( 1, []) ]\n\n","type":"List.List a -> List.List ( a, List.List a )"},{"name":"groupWhile","comment":" Group elements together, using a custom comparison test (`a -> a -> Bool`). Start a new group each time the comparison test doesn't hold for two adjacent elements.\n\n`groupWhile` uses a non-empty list type `(a, List a)` since groups necessarily must have at least one member since they are determined by comparing two members.\n\n groupWhile\n (==)\n [ 1, 2, 3 ]\n --> [ ( 1, [] ), ( 2, [] ), ( 3, [] ) ]\n\n groupWhile\n (<)\n [ 1, 2, 3, 2, 4, 1, 3, 2, 1 ]\n --> [ ( 1, [ 2, 3 ] ), ( 2, [ 4 ] ), ( 1, [ 3 ] ), ( 2, [] ), ( 1, [] ) ]\n\n groupWhile\n (\\a b -> a.id == b.id)\n [ { value = 4, id = 9 }, { value = 7, id = 2 }, { value = 1, id = 2 } ]\n --> [ ( { value = 4, id = 9 }, [] ), ( { value = 7, id = 2 }, [ { value = 1, id = 2 } ] ) ]\n\n**Note:**\nThe behavior of this function has changed between major versions 7 and 8. In version 7 there was `groupWhile` and `groupWhileTransitively`. The behavior of the two was almost identical, however the transitive function was closer to what users found intuitive about grouping. `groupWhileTransitively` has been deleted, and `groupWhile` has been replaced with the version 7s `groupWhileTransitively` behavior. Furthermore the group type was changed from `List a` to the non-empty list type `(a, List a)`. Sorry for any inconvenience this may cause.\n\n","type":"(a -> a -> Basics.Bool) -> List.List a -> List.List ( a, List.List a )"},{"name":"groupsOf","comment":" Split list into groups of length `size`. If there are not enough elements\nto completely fill the last group, it will not be included. This is equivalent\nto calling `groupsOfWithStep` with the same `size` and `step`.\n\n groupsOf 3 (List.range 1 10)\n --> [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ]\n\n","type":"Basics.Int -> List.List a -> List.List (List.List a)"},{"name":"groupsOfVarying","comment":" `groupsOfVarying ns` takes `n` elements from a list for each `n` in `ns`, splitting the list into variably sized segments\n\n groupsOfVarying [ 2, 3, 1 ] [ \"a\", \"b\", \"c\", \"d\", \"e\", \"f\" ]\n --> [ [ \"a\", \"b\" ], [ \"c\", \"d\", \"e\" ], [ \"f\" ] ]\n\n groupsOfVarying [ 2 ] [ \"a\", \"b\", \"c\", \"d\", \"e\", \"f\" ]\n --> [ [ \"a\", \"b\" ] ]\n\n groupsOfVarying [ 2, 3, 1, 5, 6 ] [ \"a\", \"b\", \"c\", \"d\", \"e\" ]\n --> [ [ \"a\", \"b\" ], [ \"c\", \"d\", \"e\" ] ]\n\n","type":"List.List Basics.Int -> List.List a -> List.List (List.List a)"},{"name":"groupsOfWithStep","comment":" Split list into groups of length `size` at offsets `step` apart. If there\nare not enough elements to completely fill the last group, it will not be\nincluded. (See `greedyGroupsOfWithStep` if you would like the last group to be\nincluded regardless.)\n\n groupsOfWithStep 4 4 (List.range 1 10)\n --> [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ] ]\n\n groupsOfWithStep 3 1 (List.range 1 5)\n --> [ [ 1, 2, 3 ], [ 2, 3, 4 ], [ 3, 4, 5 ] ]\n\n groupsOfWithStep 3 6 (List.range 1 20)\n --> [ [ 1, 2, 3 ], [ 7, 8, 9 ], [ 13, 14, 15 ] ]\n\nIf `step == size`, every element (except for perhaps the last few due to the\nnon-greedy behavior) will appear in exactly one group. If `step < size`, there\nwill be an overlap between groups. If `step > size`, some elements will be\nskipped and not appear in any groups.\n\n","type":"Basics.Int -> Basics.Int -> List.List a -> List.List (List.List a)"},{"name":"indexedFoldl","comment":" Variant of `foldl` that passes the index of the current element to the step function. `indexedFoldl` is to `List.foldl` as `List.indexedMap` is to `List.map`.\n","type":"(Basics.Int -> a -> b -> b) -> b -> List.List a -> b"},{"name":"indexedFoldr","comment":" Variant of `foldr` that passes the index of the current element to the step function. `indexedFoldr` is to `List.foldr` as `List.indexedMap` is to `List.map`.\n","type":"(Basics.Int -> a -> b -> b) -> b -> List.List a -> b"},{"name":"init","comment":" Return all elements of the list except the last one.\n\n init [ 1, 2, 3 ]\n --> Just [ 1, 2 ]\n\n init []\n --> Nothing\n\n","type":"List.List a -> Maybe.Maybe (List.List a)"},{"name":"initialize","comment":" Initialize a list of some length with some function.\n\n`initialize n f` creates a list of length `n` with the element at index `i` initialized to the result of `f i`.\n\n","type":"Basics.Int -> (Basics.Int -> a) -> List.List a"},{"name":"inits","comment":" Return all initial segments of a list, from shortest to longest, empty list first, the list itself last.\n\n inits [ 1, 2, 3 ]\n --> [ [], [ 1 ], [ 1, 2 ], [ 1, 2, 3 ] ]\n\n","type":"List.List a -> List.List (List.List a)"},{"name":"intercalate","comment":" Take a list and a list of lists, insert that list between every list in the list of lists, concatenate the result. `intercalate xs xss` is equivalent to `concat (intersperse xs xss)`.\n\n intercalate [ 0, 0 ] [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ] ]\n --> [ 1, 2, 0, 0, 3, 4, 0, 0, 5, 6 ]\n\n","type":"List.List a -> List.List (List.List a) -> List.List a"},{"name":"interweave","comment":" Return a list that contains elements from the two provided, in alternate order.\nIf one list runs out of items, append the items from the remaining list.\n\n interweave [ 1, 3 ] [ 2, 4 ]\n --> [ 1, 2, 3, 4 ]\n\n interweave [ 1, 3, 5, 7 ] [ 2, 4 ]\n --> [ 1, 2, 3, 4, 5, 7 ]\n\n interweave [ 4, 9, 16 ] [ 2, 3, 5, 7 ]\n --> [ 4, 2, 9, 3, 16, 5, 7 ]\n\n","type":"List.List a -> List.List a -> List.List a"},{"name":"isInfixOf","comment":" Return True if all the elements of the first list occur in-order and\nconsecutively anywhere within the second.\n\n isInfixOf [ 5, 7, 11 ] [ 2, 3, 5, 7, 11, 13 ]\n --> True\n\n isInfixOf [ 5, 7, 13 ] [ 2, 3, 5, 7, 11, 13 ]\n --> False\n\n isInfixOf [ 3, 5, 2 ] [ 2, 3, 5, 7, 11, 13 ]\n --> False\n\n","type":"List.List a -> List.List a -> Basics.Bool"},{"name":"isPermutationOf","comment":" Take two lists and return `True`, if the first list is a permutation of the second list.\nIn other words: Do the 2 `List`s contain the same elements but in a different order?\n\n [ 3, 1, 2 ]\n |> isPermutationOf\n [ 1, 2, 3 ]\n --> True\n\n [ 3, 1, 0 ]\n |> isPermutationOf\n [ 1, 2, 3 ]\n --> False\n\n [ 3, 1, 2, 2 ]\n |> isPermutationOf\n [ 1, 2, 3 ]\n --> False\n\n","type":"List.List a -> List.List a -> Basics.Bool"},{"name":"isPrefixOf","comment":" Take two lists and return `True`, if the first list is the prefix of the second list.\n","type":"List.List a -> List.List a -> Basics.Bool"},{"name":"isSubsequenceOf","comment":" Return True if all the elements of the first list occur, in order, in the\nsecond. The elements do not have to occur consecutively.\n\n isSubsequenceOf\n [ \"E\", \"l\", \"m\" ]\n [ \"E\", \"a\", \"t\", \" \", \"l\", \"i\", \"m\", \"e\", \"s\" ]\n --> True\n\n isSubsequenceOf\n [ \"E\", \"l\", \"m\" ]\n [ \"E\", \"m\", \"a\", \"i\", \"l\" ]\n --> False\n\n","type":"List.List a -> List.List a -> Basics.Bool"},{"name":"isSuffixOf","comment":" Take two lists and return `True`, if the first list is the suffix of the second list.\n","type":"List.List a -> List.List a -> Basics.Bool"},{"name":"iterate","comment":" Returns a list of repeated applications of `f`. If `f` returns `Nothing`\nthe iteration will stop. If it returns `Just y` then `y` will be added to the\nlist and the iteration will continue with `f y`.\n\n collatz : Int -> Maybe Int\n collatz n =\n if n == 1 then\n Nothing\n else\n Just <|\n if modBy 2 n == 0 then\n n // 2\n else\n 3 * n + 1\n\n iterate collatz 13\n --> [13,40,20,10,5,16,8,4,2,1]\n\n","type":"(a -> Maybe.Maybe a) -> a -> List.List a"},{"name":"joinOn","comment":" Performs an inner join, combining data items from both lists if they match by their respective key functions.\n\n employees : List { name : String, departmentId : Int }\n employees =\n [ { name = \"Rafferty\", departmentId = 31 }\n , { name = \"Jones\", departmentId = 33 }\n , { name = \"Heisenberg\", departmentId = 33 }\n , { name = \"Robinson\", departmentId = 34 }\n , { name = \"Smith\", departmentId = 34 }\n ]\n\n departments : List { name : String, departmentId : Int }\n departments =\n [ { departmentId = 31, name = \"Sales\" }\n , { departmentId = 33, name = \"Engineering\" }\n , { departmentId = 34, name = \"Clerical\" }\n , { departmentId = 35, name = \"Marketing\" }\n ]\n\n joinOn (\\empl dep -> { employee = empl.name, department = dep.name}) .departmentId .departmentId employees departments\n --> [ { department = \"Clerical\", employee = \"Robinson\" }\n --> , { department = \"Clerical\", employee = \"Smith\" }\n --> , { department = \"Engineering\", employee = \"Jones\" }\n --> , { department = \"Engineering\", employee = \"Heisenberg\" }\n --> , { department = \"Sales\", employee = \"Rafferty\" }\n --> ]\n\nThis is akin to the SQL query:\n\n SELECT employee.name, department.name\n FROM employee\n INNER JOIN department\n ON employee.departmentId = department.departmentId\n\n","type":"(a -> b -> c) -> (a -> comparable) -> (b -> comparable) -> List.List a -> List.List b -> List.List c"},{"name":"last","comment":" Extract the last element of a list.\n\n last [ 1, 2, 3 ]\n --> Just 3\n\n last []\n --> Nothing\n\n","type":"List.List a -> Maybe.Maybe a"},{"name":"lift2","comment":" Map functions taking multiple arguments over multiple lists, regardless of list length.\nAll possible combinations will be explored.\n\n lift2 (+) [1,2,3][4,5]\n --> [5,6,6,7,7,8]\n\n","type":"(a -> b -> c) -> List.List a -> List.List b -> List.List c"},{"name":"lift3","comment":" Maps a function over three lists, exploring all possible combinations.\n","type":"(a -> b -> c -> d) -> List.List a -> List.List b -> List.List c -> List.List d"},{"name":"lift4","comment":" Maps a function over four lists, exploring all possible combinations.\n","type":"(a -> b -> c -> d -> e) -> List.List a -> List.List b -> List.List c -> List.List d -> List.List e"},{"name":"mapAccuml","comment":" The mapAccuml function behaves like a combination of map and foldl; it applies a\nfunction to each element of a list, passing an accumulating parameter from left to right,\nand returning a final value of this accumulator together with the new list.\n\n mapAccuml f a0 [ x1, x2, x3 ] == ( a3, [ y1, y2, y3 ] )\n\n -- x1 x2 x3\n -- | | |\n -- a0 -- f --- f --- f -> a3\n -- | | |\n -- y1 y2 y3\n\nAdd a running total to a list of numbers:\n\n mapAccuml (\\a x -> ( a + x, ( x, a + x ) )) 0 [ 2, 4, 8 ]\n --> ( 14, [ ( 2, 2 ), ( 4, 6 ), ( 8, 14 ) ] )\n\nMap number by multiplying with accumulated sum:\n\n mapAccuml (\\a x -> ( a + x, a * x )) 5 [ 2, 4, 8 ]\n --> ( 19, [ 10, 28, 88 ] )\n\n","type":"(a -> b -> ( a, c )) -> a -> List.List b -> ( a, List.List c )"},{"name":"mapAccumr","comment":" The mapAccumr function behaves like a combination of map and foldr; it applies a\nfunction to each element of a list, passing an accumulating parameter from right to left,\nand returning a final value of this accumulator together with the new list.\n\n mapAccumr f a0 [ x1, x2, x3 ] == ( a3, [ y1, y2, y3 ] )\n\n -- x1 x2 x3\n -- | | |\n -- a3 <- f --- f --- f -- a0\n -- | | |\n -- y1 y2 y3\n\nAdd a count of remaining elements:\n\n mapAccumr (\\a x -> ( a + 1, ( x, a ) )) 0 [ 2, 4, 8 ]\n --> ( 3, [ ( 2, 2 ), ( 4, 1 ), ( 8, 0 ) ] )\n\nMap number by multiplying with right-to-left accumulated sum:\n\n mapAccumr (\\a x -> ( a + x, a * x )) 5 [ 2, 4, 8 ]\n --> ( 19, [ 34, 52, 40 ] )\n\n","type":"(a -> b -> ( a, c )) -> a -> List.List b -> ( a, List.List c )"},{"name":"maximumBy","comment":" Find the first maximum element in a list using a comparable transformation\n","type":"(a -> comparable) -> List.List a -> Maybe.Maybe a"},{"name":"maximumWith","comment":" Find the first maximum element in a list using a comparison function\n\n maximumWith compare []\n --> Nothing\n\n maximumWith\n (\\x y -> compare x.val y.val)\n [{id=1, val=1}, {id=2, val=2}, {id=3,val=2}]\n --> Just { id = 2, val = 2 }\n\n","type":"(a -> a -> Basics.Order) -> List.List a -> Maybe.Maybe a"},{"name":"minimumBy","comment":" Find the first minimum element in a list using a comparable transformation\n","type":"(a -> comparable) -> List.List a -> Maybe.Maybe a"},{"name":"minimumWith","comment":" Find the first minimum element in a list using a comparison function\n\n minimumWith compare []\n --> Nothing\n minimumWith\n (\\x y -> compare x.val y.val)\n [{id=1, val=2}, {id=2, val=1}, {id=3,val=1}]\n --> Just { id = 2, val = 1 }\n\n","type":"(a -> a -> Basics.Order) -> List.List a -> Maybe.Maybe a"},{"name":"notMember","comment":" Negation of `member`.\n\n notMember 1 [ 1, 2, 3 ]\n --> False\n\n notMember 4 [ 1, 2, 3 ]\n --> True\n\n","type":"a -> List.List a -> Basics.Bool"},{"name":"permutations","comment":" Return the list of of all permutations of a list. The result is in lexicographic order.\n\n permutations [ 1, 2, 3 ]\n --> [ [ 1, 2, 3 ], [ 1, 3, 2 ], [ 2, 1, 3 ], [ 2, 3, 1 ], [ 3, 1, 2 ], [ 3, 2, 1 ] ]\n\n","type":"List.List a -> List.List (List.List a)"},{"name":"remove","comment":" Remove the first occurrence of a value from a list.\n","type":"a -> List.List a -> List.List a"},{"name":"removeAt","comment":" Remove the element at an index from a list. Return the original list if the index is out of range.\n\n removeAt 0 [ 1, 2, 3 ]\n --> [ 2, 3 ]\n\nSee also `removeIfIndex`.\n\n","type":"Basics.Int -> List.List a -> List.List a"},{"name":"removeIfIndex","comment":" Remove an element at an index that satisfies a predicate.\n\n removeIfIndex ((==) 2) [ 1, 2, 3 ]\n --> [ 1, 2 ]\n\nSee also `removeAt`.\n\n","type":"(Basics.Int -> Basics.Bool) -> List.List a -> List.List a"},{"name":"reverseFilter","comment":" `reverseMap f xs` gives the same result as `List.reverse (List.map f xs)`,\nbut is tail-recursive and slightly more efficient.\n\n reverseFilter (\\x -> x > 5) [ 1, 4, 9, 16]\n --> [ 16, 9 ]\n\n","type":"(a -> Basics.Bool) -> List.List a -> List.List a"},{"name":"reverseMap","comment":" `reverseMap f xs` gives the same result as `List.reverse (List.map f xs)`,\nbut is tail-recursive and slightly more efficient.\n\n reverseMap sqrt [ 1, 4, 9 ]\n --> [ 3, 2, 1 ]\n\n","type":"(a -> b) -> List.List a -> List.List b"},{"name":"reverseRange","comment":" Create a list of numbers, every element decreasing by one.\nYou give the highest and lowest number that should be in the list.\nMore efficient than calling `List.reverse (List.range lo hi)`\n\n range 6 3 == [ 6, 5, 4, 3 ]\n\n range 3 3 == [ 3 ]\n\n range 3 6 == []\n\n","type":"Basics.Int -> Basics.Int -> List.List Basics.Int"},{"name":"scanl","comment":" Reduce a list from the left, building up all of the intermediate results into a list.\n\n scanl (+) 0 [ 1, 2, 3, 4 ]\n --> [ 0, 1, 3, 6, 10 ]\n\n","type":"(a -> b -> b) -> b -> List.List a -> List.List b"},{"name":"scanl1","comment":" `scanl1` is a variant of `scanl` that has no starting value argument.\n\nCompare:\n\n scanl (+) 0 [ 1, 2, 3 ]\n --> [ 0, 1, 3, 6 ]\n\n scanl1 (+) [ 1, 2, 3 ]\n --> [ 1, 3, 6 ]\n\n scanl (-) 0 [ 1, 2, 3 ]\n --> [ 0, 1, 1, 2 ]\n\n scanl1 (-) [ 1, 2, 3 ]\n --> [ 1, 1, 2 ]\n\n","type":"(a -> a -> a) -> List.List a -> List.List a"},{"name":"scanr","comment":" `scanr` is a right-to-left dual of `scanl`. Note that:\n\n head (scanr f z xs) == foldr f z xs\n\nExamples:\n\n scanr (+) 0 [ 1, 2, 3 ]\n --> [ 6, 5, 3, 0 ]\n\n scanr (-) 0 [ 1, 2, 3 ]\n --> [ 2, -1, 3, 0 ]\n\n","type":"(a -> b -> b) -> b -> List.List a -> List.List b"},{"name":"scanr1","comment":" `scanr1` is a variant of `scanr` that has no starting value argument.\n\n scanr1 (+) [ 1, 2, 3 ]\n --> [ 6, 5, 3 ]\n\n scanr1 (-) [ 1, 2, 3 ]\n --> [ 2, -1, 3 ]\n\n","type":"(a -> a -> a) -> List.List a -> List.List a"},{"name":"select","comment":" Return all combinations in the form of (element, rest of the list). Read [Haskell Libraries proposal](https://mail.haskell.org/pipermail/libraries/2008-February/009270.html) for further ideas on how to use this function.\n\n select [ 1, 2, 3, 4 ]\n --> [ ( 1, [ 2, 3, 4 ] ), ( 2, [ 1, 3, 4 ] ), ( 3, [ 1, 2, 4 ] ), ( 4, [ 1, 2, 3 ] ) ]\n\n","type":"List.List a -> List.List ( a, List.List a )"},{"name":"selectSplit","comment":" Return all combinations in the form of (elements before, element, elements after).\n\n selectSplit [ 1, 2, 3 ]\n --> [ ( [], 1, [ 2, 3 ] ), ( [ 1 ], 2, [ 3 ] ), ( [ 1, 2 ], 3, [] ) ]\n\n","type":"List.List a -> List.List ( List.List a, a, List.List a )"},{"name":"setAt","comment":" Set a value in a list by index. Return the original list if the index is out of range.\n\n setAt 0 42 [ 1, 2, 3 ]\n --> [ 42, 2, 3 ]\n\n","type":"Basics.Int -> a -> List.List a -> List.List a"},{"name":"setIf","comment":" Replace all values that satisfy a predicate with a replacement value.\n","type":"(a -> Basics.Bool) -> a -> List.List a -> List.List a"},{"name":"span","comment":" Take a predicate and a list, return a tuple. The first part of the tuple is the longest prefix of that list, for each element of which the predicate holds. The second part of the tuple is the remainder of the list. `span p xs` is equivalent to `(takeWhile p xs, dropWhile p xs)`.\n\n span ((>) 3) [ 1, 2, 3, 4, 1, 2, 3, 4 ]\n --> ( [ 1, 2 ], [ 3, 4, 1, 2, 3, 4 ] )\n\n span ((>) 5) [ 1, 2, 3 ]\n --> ( [ 1, 2, 3 ], [] )\n\n span ((>) 0) [ 1, 2, 3 ]\n --> ( [], [ 1, 2, 3 ] )\n\n","type":"(a -> Basics.Bool) -> List.List a -> ( List.List a, List.List a )"},{"name":"splitAt","comment":" Take a number and a list, return a tuple of lists, where first part is prefix of the list of length equal the number, and second part is the remainder of the list. `splitAt n xs` is equivalent to `(take n xs, drop n xs)`.\n\n splitAt 3 [ 1, 2, 3, 4, 5 ]\n --> ( [ 1, 2, 3 ], [ 4, 5 ] )\n\n splitAt 1 [ 1, 2, 3 ]\n --> ( [ 1 ], [ 2, 3 ] )\n\n splitAt 3 [ 1, 2, 3 ]\n --> ( [ 1, 2, 3 ], [] )\n\n splitAt 4 [ 1, 2, 3 ]\n --> ( [ 1, 2, 3 ], [] )\n\n splitAt 0 [ 1, 2, 3 ]\n --> ( [], [ 1, 2, 3 ] )\n\n splitAt -1 [ 1, 2, 3 ]\n --> ( [], [ 1, 2, 3 ] )\n\n","type":"Basics.Int -> List.List a -> ( List.List a, List.List a )"},{"name":"splitWhen","comment":" Attempts to split the list at the first element where the given predicate is true. If the predicate is not true for any elements in the list, return nothing. Otherwise, return the split list.\n\n splitWhen (\\n -> n == 3) [ 1, 2, 3, 4, 5 ]\n --> Just ( [ 1, 2 ], [ 3, 4, 5 ] )\n\n splitWhen (\\n -> n == 6) [ 1, 2, 3, 4, 5 ]\n --> Nothing\n\n","type":"(a -> Basics.Bool) -> List.List a -> Maybe.Maybe ( List.List a, List.List a )"},{"name":"stableSortWith","comment":" Similar to List.sortWith, this sorts values with a custom comparison function.\nUnlike List.sortWith, this sort is guaranteed to be a stable sort.\nNote that List.sortWith is faster and is preferred if sort stability is not required.\n","type":"(a -> a -> Basics.Order) -> List.List a -> List.List a"},{"name":"stoppableFoldl","comment":" A `foldl` that can stop early instead of traversing the whole list.\n\n stoppableFoldl\n (\\n acc ->\n if acc >= 50 then\n Stop acc\n else\n Continue (n + acc)\n )\n 0\n (List.range 1 10000)\n --> 55\n\n","type":"(a -> b -> List.Extra.Step b) -> b -> List.List a -> b"},{"name":"stripPrefix","comment":" Drop the given prefix from the list. If the list doesn't start with that prefix, return `Nothing`.\n\n stripPrefix [ 1, 2 ] [ 1, 2, 3, 4 ]\n --> Just [ 3, 4 ]\n\n stripPrefix [ 1, 2, 3 ] [ 1, 2, 3, 4, 5 ]\n --> Just [ 4, 5 ]\n\n stripPrefix [ 1, 2, 3 ] [ 1, 2, 3 ]\n --> Just []\n\n stripPrefix [ 1, 2, 3 ] [ 1, 2 ]\n --> Nothing\n\n stripPrefix [ 3, 2, 1 ] [ 1, 2, 3, 4, 5 ]\n --> Nothing\n\n","type":"List.List a -> List.List a -> Maybe.Maybe (List.List a)"},{"name":"subsequences","comment":" Return the list of all subsequences of a list.\n\n subsequences [ 1, 2, 3 ]\n --> [ [], [ 1 ], [ 2 ], [ 1, 2 ], [ 3 ], [ 1, 3 ], [ 2, 3 ], [ 1, 2, 3 ] ]\n\n","type":"List.List a -> List.List (List.List a)"},{"name":"subsequencesNonEmpty","comment":" Return the list of all subsequences of the argument, except for the empty list.\n\n subsequencesNonEmpty [ 1, 2, 3 ]\n == [ [ 1 ], [ 2 ], [ 1, 2 ], [ 3 ], [ 1, 3 ], [ 2, 3 ], [ 1, 2, 3 ] ]\n\n","type":"List.List a -> List.List ( a, List.List a )"},{"name":"swapAt","comment":" Swap two values in a list by index. Return the original list if the index is out of range.\nIf the same index is supplied twice the operation has no effect.\n\n swapAt 1 2 [ 1, 2, 3 ]\n --> [ 1, 3, 2 ]\n\n","type":"Basics.Int -> Basics.Int -> List.List a -> List.List a"},{"name":"tails","comment":" Return all final segments of a list, from longest to shortest, the list itself first, empty list last.\n\n tails [ 1, 2, 3 ]\n --> [ [ 1, 2, 3 ], [ 2, 3 ], [ 3 ], [] ]\n\n","type":"List.List a -> List.List (List.List a)"},{"name":"takeWhile","comment":" Take elements in order as long as the predicate evaluates to `True`\n","type":"(a -> Basics.Bool) -> List.List a -> List.List a"},{"name":"takeWhileRight","comment":" Take elements from the right, while predicate still holds.\n\n takeWhileRight ((<) 5) (List.range 1 10)\n --> [ 6, 7, 8, 9, 10 ]\n\n","type":"(a -> Basics.Bool) -> List.List a -> List.List a"},{"name":"transpose","comment":" Transpose rows and columns of the list of lists.\n\n transpose [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]\n --> [ [ 1, 4 ], [ 2, 5 ], [ 3, 6 ] ]\n\n transpose [ [ 10, 11 ], [ 20, 40 ], [ 30, 31, 32, 400 ] ]\n --> [ [ 10, 20, 30 ], [ 11, 40, 31 ] ]\n\n","type":"List.List (List.List a) -> List.List (List.List a)"},{"name":"uncons","comment":" Decompose a list into its head and tail. If the list is empty, return `Nothing`. Otherwise, return `Just (x, xs)`, where `x` is head and `xs` is tail.\n\n uncons [1,2,3]\n --> Just (1, [2,3])\n\n uncons []\n --> Nothing\n\n","type":"List.List a -> Maybe.Maybe ( a, List.List a )"},{"name":"unconsLast","comment":" Decompose a list into its body and last element. If the list is empty, return `Nothing`. Otherwise, return `Just (x, xs)`, where `x` is the last element and `xs` is the body.\n\n unconsLast [1,2,3]\n --> Just (3, [1,2])\n\n unconsLast []\n --> Nothing\n\n","type":"List.List a -> Maybe.Maybe ( a, List.List a )"},{"name":"unfoldr","comment":" The `unfoldr` function is \"dual\" to `foldr`. `foldr` reduces a list to a summary value, `unfoldr` builds a list from a seed. The function takes a function and a starting element. It applies the function to the element. If the result is `Just (a, b)`, `a` is accumulated and the function is applied to `b`. If the result is `Nothing`, the list accumulated so far is returned.\n\n subtractOneUntilZero : Int -> Maybe (Int, Int)\n subtractOneUntilZero i =\n if i /= 0 then\n Just (i, i - 1)\n else\n Nothing\n\n unfoldr subtractOneUntilZero 5\n --> [ 5, 4, 3, 2, 1 ]\n\n","type":"(b -> Maybe.Maybe ( a, b )) -> b -> List.List a"},{"name":"unique","comment":" Remove duplicate values, keeping the first instance of each element which appears more than once.\n\n unique [ 0, 1, 1, 0, 1 ]\n --> [ 0, 1 ]\n\n","type":"List.List a -> List.List a"},{"name":"uniqueBy","comment":" Drop duplicates where what is considered to be a duplicate is the result of first applying the supplied function to the elements of the list.\n","type":"(a -> b) -> List.List a -> List.List a"},{"name":"uniquePairs","comment":" Return all ways to pair the elements of the list.\n(Essentially, enumerate the possible \"handshakes.\")\n\nThe order of the pair elements doesn't matter, so if `(1,2)` is a returned pair,\nwe don't return `(2,1)`.\n\nIn more mathematical terms these are 2-combinations without repetition.\n\n uniquePairs [ 1, 2, 3, 4 ]\n --> [ ( 1, 2 ), ( 1, 3 ), ( 1, 4 ), ( 2, 3 ), ( 2, 4 ), ( 3, 4 ) ]\n\nIn this example, everybody shakes hands with three other people.\n\n","type":"List.List a -> List.List ( a, a )"},{"name":"updateAt","comment":" Replace a value at a specific index by calling an update function. Return the original list if the index is out of range.\n\n updateAt 0 ((+) 1) [ 1, 2, 3 ]\n --> [ 2, 2, 3 ]\n\nSee also `updateIfIndex`.\n\n","type":"Basics.Int -> (a -> a) -> List.List a -> List.List a"},{"name":"updateIf","comment":" Replace all values that satisfy a predicate by calling an update function.\n","type":"(a -> Basics.Bool) -> (a -> a) -> List.List a -> List.List a"},{"name":"updateIfIndex","comment":" Replace a value at an index that satisfies a predicate, by calling an update function.\n\n updateIfIndex ((==) 2) ((+) 1) [ 1, 2, 3 ]\n --> [ 1, 2, 4 ]\n\nSee also `updateAt`.\n\n","type":"(Basics.Int -> Basics.Bool) -> (a -> a) -> List.List a -> List.List a"},{"name":"zip","comment":" Take two lists and returns a list of corresponding pairs\n","type":"List.List a -> List.List b -> List.List ( a, b )"},{"name":"zip3","comment":" Take three lists and returns a list of triples\n","type":"List.List a -> List.List b -> List.List c -> List.List ( a, b, c )"}],"binops":[]},{"name":"Maybe.Extra","comment":" Convenience functions for [`Maybe`](https://package.elm-lang.org/packages/elm/core/latest/Maybe).\n\n\n# Basics\n\nWork with 1 `Maybe`\n\n@docs isJust, isNothing, join, filter\n\n\n# Get a value out of a `Maybe`\n\n@docs withDefaultLazy, unwrap, unpack\n\n\n# OR based logic\n\nTake the first value that's present\n\n@docs or, orElse, orList, orLazy, orElseLazy, orListLazy, oneOf\n\n\n# Lists of `Maybe`s\n\n@docs values\n@docs combine, traverse, combineArray, traverseArray\n\n\n# Transforming to collections\n\n@docs toList, toArray\n@docs cons\n\n\n# andThenN\n\nThese functions are just like [`andThen`](https://package.elm-lang.org/packages/elm/core/latest/Maybe#andThen), except they take multiple arguments.\n\nAll arguments must be `Just` and the function must return a `Just` for the result to be `Just`.\n\nIf you need a version of `andThenN` that takes more than 4 arguments, you can chain together [`andMap`](#andMap) calls in a pipeline.\n\n@docs andThen2, andThen3, andThen4\n\n\n# Applicative Functions\n\n@docs andMap, next, prev\n\n","unions":[],"aliases":[],"values":[{"name":"andMap","comment":" If both a function and a value are present, apply the function to the value.\nIf either argument is `Nothing`, return `Nothing`.\n\n Just ((+) 2)\n |> andMap (Just 3)\n --> Just 5\n\n Nothing\n |> andMap (Just 3)\n --> Nothing\n\n Just ((+) 2)\n |> andMap Nothing\n --> Nothing\n\nThis can be used to do [`Maybe.mapN`](https://package.elm-lang.org/packages/elm/core/latest/Maybe#map2) or [`andThenN`](#andthenn) for any number of arguments.\n\n -- map4\n Just (\\a b c d -> a + b + c + d )\n |> andMap (Just 1)\n |> andMap (Just 2)\n |> andMap (Just 4)\n |> andMap (Just 8)\n --> Just 15\n\n -- andThen4\n Just (\\a b c d -> Just (a + b + c + d ))\n |> andMap (Just 1)\n |> andMap (Just 2)\n |> andMap (Just 4)\n |> andMap (Just 8)\n |> join\n --> Just 15\n\nAdvanced functional programmers will recognize this as the implementation of `<*>` for `Maybe`s from the `Applicative` typeclass.\n\n","type":"Maybe.Maybe a -> Maybe.Maybe (a -> b) -> Maybe.Maybe b"},{"name":"andThen2","comment":"\n\n import Array exposing (Array)\n\n array : Array Int\n array = Array.fromList [1,2,3]\n\n andThen2 Array.get (Just 1) (Just array)\n --> Just 2\n\n andThen2 Array.get Nothing (Just array)\n --> Nothing\n\n andThen2 Array.get (Just 1) Nothing\n --> Nothing\n\n andThen2 Array.get (Just 4) (Just array)\n --> Nothing\n\n","type":"(a -> b -> Maybe.Maybe value) -> Maybe.Maybe a -> Maybe.Maybe b -> Maybe.Maybe value"},{"name":"andThen3","comment":" `andThen` for 3 maybes.\n","type":"(a -> b -> c -> Maybe.Maybe value) -> Maybe.Maybe a -> Maybe.Maybe b -> Maybe.Maybe c -> Maybe.Maybe value"},{"name":"andThen4","comment":" `andThen` for 4 maybes.\n","type":"(a -> b -> c -> d -> Maybe.Maybe value) -> Maybe.Maybe a -> Maybe.Maybe b -> Maybe.Maybe c -> Maybe.Maybe d -> Maybe.Maybe value"},{"name":"combine","comment":" If every `Maybe` in the list is present, return all of the values unwrapped.\nIf there are any `Nothing`s, the whole function fails and returns `Nothing`.\n\n combine []\n --> Just []\n\n combine [ Just 1, Just 2, Just 3 ]\n --> Just [ 1, 2, 3 ]\n\n combine [ Just 1, Nothing, Just 3 ]\n --> Nothing\n\n","type":"List.List (Maybe.Maybe a) -> Maybe.Maybe (List.List a)"},{"name":"combineArray","comment":" Like [`combine`](#combine),\nbut works on [`Array`](https://package.elm-lang.org/packages/elm/core/latest/Array) instead of `List`.\n","type":"Array.Array (Maybe.Maybe a) -> Maybe.Maybe (Array.Array a)"},{"name":"cons","comment":" Add an item to a list only if it's a `Just`.\n\n cons (Just 1) [ 2, 3 ]\n --> [ 1, 2, 3 ]\n\n cons Nothing [2, 3 ]\n --> [ 2, 3 ]\n\n","type":"Maybe.Maybe a -> List.List a -> List.List a"},{"name":"filter","comment":" Keep the `Maybe` only if the predicate function passes\n\n filter (\\v -> v == 1) (Just 1)\n --> Just 1\n\n filter (\\v -> v == 2) (Just 1)\n --> Nothing\n\n filter (\\v -> v == 1) Nothing\n --> Nothing\n\n","type":"(a -> Basics.Bool) -> Maybe.Maybe a -> Maybe.Maybe a"},{"name":"isJust","comment":"\n\n isJust (Just 42)\n --> True\n\n isJust (Just [])\n --> True\n\n isJust Nothing\n --> False\n\n","type":"Maybe.Maybe a -> Basics.Bool"},{"name":"isNothing","comment":"\n\n isNothing (Just 42)\n --> False\n\n isNothing (Just [])\n --> False\n\n isNothing Nothing\n --> True\n\n","type":"Maybe.Maybe a -> Basics.Bool"},{"name":"join","comment":" Flattens nested `Maybe`s\n\n join (Just (Just 1))\n --> Just 1\n\n join (Just Nothing)\n --> Nothing\n\n join Nothing\n --> Nothing\n\n","type":"Maybe.Maybe (Maybe.Maybe a) -> Maybe.Maybe a"},{"name":"next","comment":" Take two `Maybe` values. If the first one equals `Nothing`, return `Nothing`. Otherwise return the second value.\n\n next (Just 1) (Just 2)\n --> Just 2\n\n next Nothing (Just 2)\n --> Nothing\n\n next (Just 1) Nothing\n --> Nothing\n\nAdvanced functional programmers will recognize this as the implementation of `*>` for `Maybe`s from the `Applicative` typeclass.\n\n","type":"Maybe.Maybe a -> Maybe.Maybe b -> Maybe.Maybe b"},{"name":"oneOf","comment":" Try a list of functions against a value. Return the value of the first call that succeeds (returns `Just`).\n\n type UserInput\n = FloatInput Float\n | IntInput Int\n | UnknownInput\n\n \"5.6\"\n |> oneOf\n [ String.toInt >> Maybe.map IntInput\n , String.toFloat >> Maybe.map FloatInput\n ]\n |> Maybe.withDefault UnknownInput\n --> FloatInput 5.6\n\n","type":"List.List (a -> Maybe.Maybe b) -> a -> Maybe.Maybe b"},{"name":"or","comment":" Returns the first value that is present, like the boolean `||`.\n\nBoth values will be computed. There is no short-circuiting.\nIf your second argument is expensive to calculate and you need short circuiting, use [`orLazy`](#orLazy) instead.\n\n or (Just 4) (Just 5)\n --> Just 4\n\n or (Just 4) Nothing\n --> Just 4\n\n or Nothing (Just 5)\n --> Just 5\n\n or Nothing Nothing\n --> Nothing\n\nAdvanced functional programmers will recognize this as the\nimplementation of `mplus` for `Maybe`s from the `MonadPlus` type\nclass.\n\n","type":"Maybe.Maybe a -> Maybe.Maybe a -> Maybe.Maybe a"},{"name":"orElse","comment":" Piping-friendly version of [`or`](#or).\n\n Just 5\n |> orElse (Just 4)\n --> Just 5\n\n orElse (Just 4) (Just 5)\n --> Just 5\n\n List.head []\n |> orElse (List.head [ 4 ])\n --> Just 4\n\n","type":"Maybe.Maybe a -> Maybe.Maybe a -> Maybe.Maybe a"},{"name":"orElseLazy","comment":" Lazy version of [`orElse`](#orElse).\nPiping-friendly version of [`orLazy`](#orLazy).\n\nThe first argument will only be evaluated if the second argument is `Nothing`.\n\n Just 4\n |> orElseLazy (\\() -> Debug.todo \"Expensive calculation\")\n --> Just 4\n\n","type":"(() -> Maybe.Maybe a) -> Maybe.Maybe a -> Maybe.Maybe a"},{"name":"orLazy","comment":" Lazy version of [`or`](#or).\n\nThe second argument will only be evaluated if the first argument is `Nothing`.\n\n orLazy (Just 4) (\\() -> Debug.todo \"Expensive calculation\")\n --> Just 4\n\n","type":"Maybe.Maybe a -> (() -> Maybe.Maybe a) -> Maybe.Maybe a"},{"name":"orList","comment":" Returns the first value that is present.\n\nAll values will be computed.\nIf your arguments are expensive to calculate, use [`orListLazy`](#orListLazy) instead.\n\n orList\n [ Nothing\n , Just 1\n , Just 2\n ]\n --> Just 1\n\n orList\n [ List.head []\n , String.toInt \"\"\n ]\n --> Nothing\n\n orList []\n --> Nothing\n\n","type":"List.List (Maybe.Maybe a) -> Maybe.Maybe a"},{"name":"orListLazy","comment":" Lazy version of [`orList`](#orList)\n\nStops calculating new values after the first match\n\n orListLazy\n [ \\() -> Nothing\n , \\() -> Just 1\n , \\() -> Debug.todo \"Expensive calculation\"\n ]\n --> Just 1\n\n","type":"List.List (() -> Maybe.Maybe a) -> Maybe.Maybe a"},{"name":"prev","comment":" Take two `Maybe` values. If the second one equals `Nothing`, return `Nothing`. Otherwise return the first value.\n\n prev (Just 1) (Just 2)\n --> Just 1\n\n prev Nothing (Just 2)\n --> Nothing\n\n prev (Just 1) Nothing\n --> Nothing\n\nAdvanced functional programmers will recognize this as the implementation of `<*` for `Maybe`s from the `Applicative` typeclass.\n\n","type":"Maybe.Maybe a -> Maybe.Maybe b -> Maybe.Maybe a"},{"name":"toArray","comment":" Like `toList`, but returns a singleton or empty [`Array`](https://package.elm-lang.org/packages/elm/core/latest/Array).\n\n import Array\n\n toArray Nothing\n --> Array.fromList []\n\n toArray (Just 1)\n --> Array.fromList [ 1 ]\n\n","type":"Maybe.Maybe a -> Array.Array a"},{"name":"toList","comment":" A `Maybe` is a lot like a list that can only be length 0 or 1.\n\nReturns a singleton list if the value is present, and an empty list it's missing.\n\n toList Nothing\n --> []\n\n toList (Just 1)\n --> [ 1 ]\n\n","type":"Maybe.Maybe a -> List.List a"},{"name":"traverse","comment":" Like [`combine`](#combine), but map a function over each element of the list first.\n\nIf every function call succeeds (returns `Just`), `traverse` will return a list.\nIf any function call fails (returns `Nothing`), `traverse` will return `Nothing`.\n\n`combine` is equivalent to `traverse identity`.\n\n traverse (\\x -> Just (x * 10)) [ 1, 2, 3, 4, 5 ]\n --> Just [ 10, 20, 30, 40, 50 ]\n\n traverse List.head [ [1], [2, 3], [] ]\n --> Nothing\n\n","type":"(a -> Maybe.Maybe b) -> List.List a -> Maybe.Maybe (List.List b)"},{"name":"traverseArray","comment":" Like [`traverse`](#traverse),\nbut works on [`Array`](https://package.elm-lang.org/packages/elm/core/latest/Array) instead of `List`.\n","type":"(a -> Maybe.Maybe b) -> Array.Array a -> Maybe.Maybe (Array.Array b)"},{"name":"unpack","comment":" Like [`unwrap`](#unwrap), but the default value is lazy,\nand will only be computed if the `Maybe` is `Nothing`.\n\n unpack (\\() -> 0) String.length Nothing\n --> 0\n\n unpack (\\() -> 0) String.length (Just \"abc\")\n --> 3\n\n`unpack (\\() -> default) f maybeX` is equivalent to\n\n case maybeX of\n Just x ->\n f x\n\n Nothing ->\n default\n\n","type":"(() -> b) -> (a -> b) -> Maybe.Maybe a -> b"},{"name":"unwrap","comment":" Like using a `case`.\nGive a function that says what to do if the input is `Just`,\nand a value to use if the input is `Nothing`.\n\nThese are all equivalent:\n\n unwrap default f maybeX\n\n maybeX\n |> Maybe.map f\n |> Maybe.withDefault default\n\n case maybeX of\n Just x ->\n f x\n\n Nothing ->\n default\n\nExcept that unlike a `case`, the default value for `unwrap` is always computed.\nIf your default value is expensive to compute, use the lazy [`unpack`](#unpack) instead.\n\nExamples:\n\n unwrap 0 String.length Nothing\n --> 0\n\n unwrap 0 String.length (Just \"abc\")\n --> 3\n\n","type":"b -> (a -> b) -> Maybe.Maybe a -> b"},{"name":"values","comment":" Take all the values that are present, throwing away any `Nothing`s.\n\nEquivalent to [`List.filterMap identity`](https://package.elm-lang.org/packages/elm/core/latest/List#filterMap).\n\n values [ Just 1, Nothing, Just 2 ]\n --> [ 1, 2 ]\n\n","type":"List.List (Maybe.Maybe a) -> List.List a"},{"name":"withDefaultLazy","comment":" Lazy version of [Maybe.withDefault](https://package.elm-lang.org/packages/elm/core/latest/Maybe#withDefault).\n\nIt will only calculate the default if needed.\n\nExamples:\n\n withDefaultLazy (\\() -> 2 + 2) Nothing\n --> 4\n\n withDefaultLazy (\\() -> Debug.todo \"Expensive calculation\") (Just 4)\n --> 4\n\n","type":"(() -> a) -> Maybe.Maybe a -> a"}],"binops":[]},{"name":"Order.Extra","comment":" Library for building comparison functions.\n\nThis library makes it easy to create comparison functions for arbitary types by composing\nsmaller comparison functions. For instance, suppose you are defining a data type to represent\na standard deck of cards. You might define it as:\n\n type alias Card =\n { value : Value, suite : Suite }\n\n type Suite\n = Clubs\n | Hearts\n | Diamonds\n | Spades\n\n type Value\n = Two\n | Three\n | Four\n | Five\n | Six\n | Seven\n | Eight\n | Nine\n | Ten\n | Jack\n | Queen\n | King\n | Ace\n\nWith this representation, you could define an ordering for `Card` values compositionally:\n\n import Order.Extra\n\n cardOrdering : Card -> Card -> Order\n cardOrdering =\n Ordering.byFieldWith suiteOrdering .suite\n |> Ordering.breakTiesWith\n (Ordering.byFieldWith valueOrdering .value)\n\n suiteOrdering : Suite -> Suite -> Order\n suiteOrdering =\n Ordering.explicit [ Clubs, Hearts, Diamonds, Spades ]\n\n valueOrdering : Value -> Value -> Order\n valueOrdering =\n Ordering.explicit\n [ Two\n , Three\n , Four\n , Five\n , Six\n , Seven\n , Eight\n , Nine\n , Ten\n , Jack\n , Queen\n , King\n , Ace\n ]\n\nYou can then use this ordering to sort cards, make comparisons, and so on. For instance,\nto sort a deck of cards you can use `cardOrdering` directly:\n\n sortCards : List Card -> List Card\n sortCards =\n List.sortWith cardOrdering\n\n\n# Construction\n\n@docs explicit, byField, byFieldWith, byRank, ifStillTiedThen\n\n\n# Composition\n\n@docs breakTiesWith, reverse\n\n\n# Strings\n\n@docs natural\n\n\n# Utility\n\n@docs isOrdered, greaterThanBy, lessThanBy\n\n","unions":[],"aliases":[],"values":[{"name":"breakTiesWith","comment":" Produces an ordering that refines the second input ordering by using the first\na -> a -> Orders a tie breaker. (Note that the second argument is the primary sort, and\nthe first argument is a tie breaker. This argument ordering is intended to support\nfunction chaining with `|>`.)\n\n type alias Point =\n { x : Int, y : Int }\n\n pointOrdering : Point -> Point -> Order\n pointOrdering =\n Order.Extra.byField .x\n |> Order.Extra.breakTiesWith (Order.Extra.byField .y)\n\n","type":"(a -> a -> Basics.Order) -> (a -> a -> Basics.Order) -> a -> a -> Basics.Order"},{"name":"byField","comment":" Produces an ordering that orders its elements using the natural ordering of the\nfield selected by the given function.\n\n type alias Point = { x : Int, y : Int }\n\n List.sortWith (Order.Extra.byField .x) [Point 3 5, Point 1 6]\n --> [Point 1 6, Point 3 5]\n List.sortWith (Order.Extra.byField .y) [Point 3 5, Point 1 6]\n --> [Point 3 5, Point 1 6]\n\n","type":"(a -> comparable) -> a -> a -> Basics.Order"},{"name":"byFieldWith","comment":" Produces an ordering that orders its elements using the given ordering on the\nfield selected by the given function.\n\n cards : List Card\n cards =\n [ Card King Hearts, Card King Hearts ]\n\n List.sortWith\n (Order.Extra.byFieldWith valueOrdering .value)\n cards\n == [ Card Two Spades, Card King Hearts]\n\n List.sortWith\n (Order.Extra.byFieldWith suiteOrdering .suite)\n cards\n == [ Card King Hearts, Card Two Spades ]\n\n","type":"(b -> b -> Basics.Order) -> (a -> b) -> a -> a -> Basics.Order"},{"name":"byRank","comment":" Produces an ordering defined by an explicit ranking function combined with a\nsecondary ordering function to compare elements within the same rank. The rule is\nthat all items are sorted first by rank, and then using the given within-rank\nordering for items of the same rank.\n\nThis function is intended for use with types that have multiple cases where\nconstructors for some or all of the cases take arguments. (Otherwise use `Ordering.explicit`\ninstead which has a simpler interface.) For instance, to make an ordering for\na type such as:\n\n type JokerCard\n = NormalCard Value Suite\n | Joker\n\nyou could use `byRank` to sort all the normal cards before the jokers like so:\n\n jokerCardOrdering : JokerCard -> JokerCard -> Order\n jokerCardOrdering =\n Order.Extra.byRank\n (\\card ->\n case card of\n NormalCard _ _ ->\n 1\n\n Joker ->\n 2\n )\n (\\x y ->\n case ( x, y ) of\n ( NormalCard v1 s1, NormalCard v2 s2 ) ->\n suiteOrdering s1 s2\n |> Order.Extra.ifStillTiedThen\n (valueOrdering v1 v2)\n\n _ ->\n EQ\n )\n\nMore generally, the expected pattern is that for each case in your type, you assign\nthat case to a unique rank with the ranking function. Then for your within-rank\nordering, you have a case statement that enumerates all the \"tie\" states and\nspecifies how to break ties, and then uses a catch-all case that returns\n`Ordering.noConflicts` to specify that all remaining cases cannot give rise to\nthe need to do any subcomparisons. (This can be either because the values being\ncompared have no internal structure and so are always equal, or because they are\nconstructors with different ranks and so will never be compared by this function.)\n\n","type":"(a -> Basics.Int) -> (a -> a -> Basics.Order) -> a -> a -> Basics.Order"},{"name":"explicit","comment":" Creates an ordering that orders items in the order given in the input list.\nItems that are not part of the input list are all considered to be equal to each\nother and less than anything in the list.\n\n type Day\n = Mon\n | Tue\n | Wed\n | Thu\n | Fri\n | Sat\n | Sun\n\n dayOrdering : Day -> Day -> Order\n dayOrdering =\n Order.Extra.explicit\n [ Mon, Tue, Wed, Thu, Fri, Sat, Sun ]\n\n","type":"List.List a -> a -> a -> Basics.Order"},{"name":"greaterThanBy","comment":" Determines if one value is greater than another according to the given ordering.\n\n greaterThanBy\n xThenYOrdering\n { x = 7, y = 8 }\n { x = 10, y = 2 }\n == False\n\n greaterThanBy\n yThenXOrdering\n { x = 7, y = 8 }\n { x = 10, y = 2 }\n == True\n\n","type":"(a -> a -> Basics.Order) -> a -> a -> Basics.Bool"},{"name":"ifStillTiedThen","comment":" Returns the main order unless it is `EQ`, in which case returns the tiebreaker.\n\nThis function does for `Order`s what `breakTiesWith` does for `Ordering`s. It is\nuseful in cases where you want to perform a cascading comparison of multiple pairs\nof values that are not wrapped in a container value, as happens when examining the\nindividual fields of a constructor.\n\n","type":"Basics.Order -> Basics.Order -> Basics.Order"},{"name":"isOrdered","comment":" Determines if the given list is ordered according to the given ordering.\n\n Order.Extra.isOrdered compare [ 1, 2, 3 ]\n --> True\n\n Order.Extra.isOrdered compare [ 2, 1, 3 ]\n --> False\n\n Order.Extra.isOrdered compare []\n --> True\n\n Order.Extra.isOrdered\n (Order.Extra.reverse compare)\n [ 1, 2, 3 ]\n --> False\n\n","type":"(a -> a -> Basics.Order) -> List.List a -> Basics.Bool"},{"name":"lessThanBy","comment":" Determines if one value is less than another according to the given ordering.\n\n lessThanBy\n xThenYOrdering\n { x = 7, y = 8 }\n { x = 10, y = 2 }\n == True\n\n lessThanBy\n yThenXOrdering\n { x = 7, y = 8 }\n { x = 10, y = 2 }\n == False\n\n","type":"(a -> a -> Basics.Order) -> a -> a -> Basics.Bool"},{"name":"natural","comment":" Compare two strings naturally.\n\n List.sortWith Order.Extra.natural [\"a10\", \"a2\"]\n --> [\"a2\", \"a10\"]\n\nWithout full I18n support, this is probably the best way to sort\nuser provided strings in a way that is intuitive to humans.\n\n","type":"String.String -> String.String -> Basics.Order"},{"name":"reverse","comment":" Returns an ordering that reverses the input ordering.\n\n List.sortWith\n (Order.Extra.reverse compare)\n [ 1, 2, 3, 4, 5 ]\n --> [ 5, 4, 3, 2, 1 ]\n\n","type":"(a -> a -> Basics.Order) -> a -> a -> Basics.Order"}],"binops":[]},{"name":"Result.Extra","comment":" Convenience functions for working with `Result`.\n\n\n# Common Helpers\n\n@docs isOk, isErr, extract, unwrap, unpack, error, mapBoth, merge, join, partition, filter\n\n\n# Combining\n\n@docs combine, combineMap, combineFirst, combineSecond, combineBoth, combineMapFirst, combineMapSecond, combineMapBoth\n\n\n# Applying\n\n@docs singleton, andMap\n\n\n# Alternatives\n\n@docs or, orLazy, orElseLazy, orElse\n\n\n# Conversions\n\n@docs toTask\n\n","unions":[],"aliases":[],"values":[{"name":"andMap","comment":" Apply the function that is inside `Result` to a value that is inside\n`Result`. Return the result inside `Result`. If one of the `Result`\narguments is `Err e`, return `Err e`. Also known as `apply`.\n\n Err \"Oh\" |> andMap (Err \"No!\") == Err \"Oh\"\n\n Err \"Oh\" |> andMap (Ok 2) == Err \"Oh\"\n\n Ok ((+) 1) |> andMap (Err \"No!\") == Err \"No!\"\n\n Ok ((+) 1) |> andMap (Ok 2) == Ok 3\n\n","type":"Result.Result e a -> Result.Result e (a -> b) -> Result.Result e b"},{"name":"combine","comment":" Combine a list of results into a single result (holding a list).\nAlso known as `sequence` on lists.\n","type":"List.List (Result.Result x a) -> Result.Result x (List.List a)"},{"name":"combineBoth","comment":" Combine all results in a tuple\ninto a single result holding the tuple's values.\nAlso know as `bisequence` on tuples.\n","type":"( Result.Result x a, Result.Result x b ) -> Result.Result x ( a, b )"},{"name":"combineFirst","comment":" Pull a result out of the _first_ element of a tuple\nand combine it into a result holding the tuple's values.\n","type":"( Result.Result x a, c ) -> Result.Result x ( a, c )"},{"name":"combineMap","comment":" Map a function producing results on a list\nand combine those into a single result (holding a list).\nAlso known as `traverse` on lists.\n\n combineMap f xs == combine (List.map f xs)\n\n","type":"(a -> Result.Result x b) -> List.List a -> Result.Result x (List.List b)"},{"name":"combineMapBoth","comment":" Map a function producing results on the _both_ elements of a tuple\nand then pull them out using `combineBoth`.\nAlso know as `bitraverse` on tuples.\n\n combineMapBoth f g ( x, y )\n == combineBoth (Tuple.mapBoth f g ( x, y ))\n == Result.map2 Tuple.pair (f x) (g y)\n\n","type":"(a -> Result.Result x c) -> (b -> Result.Result x d) -> ( a, b ) -> Result.Result x ( c, d )"},{"name":"combineMapFirst","comment":" Map a function producing results on the _first_ element of a tuple\nand then pull it out using `combineFirst`.\nAlso know as `sequence` on tuples.\n\n combineMapFirst f ( x, y )\n == combineFirst (Tuple.mapFirst f ( x, y ))\n == Result.map (\\newX -> ( newX, y )) (f x)\n\n","type":"(a -> Result.Result x b) -> ( a, c ) -> Result.Result x ( b, c )"},{"name":"combineMapSecond","comment":" Map a function producing results on the _second_ element of a tuple\nand then pull it out using `combineSecond`.\nAlso know as `traverse` on tuples.\n\n combineMapSecond f ( x, y )\n == combineSecond (Tuple.mapSecond f ( x, y ))\n == Result.map (Tuple.pair x) (f y)\n\n","type":"(a -> Result.Result x b) -> ( c, a ) -> Result.Result x ( c, b )"},{"name":"combineSecond","comment":" Pull a result out of the _second_ element of a tuple\nand combine it into a result holding the tuple's values.\nAlso known as `sequence` on tuples.\n","type":"( c, Result.Result x a ) -> Result.Result x ( c, a )"},{"name":"error","comment":" Convert to a Maybe containing the error, if there is one.\n\n parseInt : String -> Result ParseError Int\n\n maybeParseError : String -> Maybe ParseError\n maybeParseError string =\n error (parseInt string)\n\n","type":"Result.Result e a -> Maybe.Maybe e"},{"name":"extract","comment":" Turn a `Result e a` to an `a`, by applying the conversion\nfunction specified to the `e`.\n","type":"(e -> a) -> Result.Result e a -> a"},{"name":"filter","comment":" Take a `Result` and a predicate function and return a `Result` with the\noriginal value when a predicate matches.\n\n filter \"is not 1\" (\\v -> v == 1) (Ok 1) == Ok 1\n\n filter \"is not 2\" (\\v -> v == 2) (Ok 1) == Err \"is not 2\"\n\n","type":"e -> (a -> Basics.Bool) -> Result.Result e a -> Result.Result e a"},{"name":"isErr","comment":" Check whether the result is `Err` without unwrapping it.\n","type":"Result.Result e a -> Basics.Bool"},{"name":"isOk","comment":" Check whether the result is `Ok` without unwrapping it.\n","type":"Result.Result e a -> Basics.Bool"},{"name":"join","comment":" Join contained results with the same error into one result.\n\nUsefull if you have a \"result in a result\":\n\n join <| Ok (Ok 4) == Ok 4\n\n join <| Ok (Err \"message\") == Err \"message\"\n\n","type":"Result.Result x (Result.Result x a) -> Result.Result x a"},{"name":"mapBoth","comment":" Apply the first argument function to an `Err` and the second\nargument function to an `Ok` of a `Result`.\n","type":"(e -> f) -> (a -> b) -> Result.Result e a -> Result.Result f b"},{"name":"merge","comment":" Eliminate Result when error and success have been mapped to the same\ntype, such as a message type.\n\n merge (Ok 4) == 4\n\n merge (Err -1) == -1\n\nMore pragmatically:\n\n type Msg\n = UserTypedInt Int\n | UserInputError String\n\n msgFromInput : String -> Msg\n msgFromInput =\n String.toInt\n >> Result.mapError UserInputError\n >> Result.map UserTypedInt\n >> Result.Extra.merge\n\n","type":"Result.Result a a -> a"},{"name":"or","comment":" Like the Boolean `||` this will return the first value that is\npositive (`Ok`). However, unlike with `||`, both values will be\ncomputed anyway (there is no short-circuiting).\n\n or (Ok 4) (Ok 5) == Ok 4\n\n or (Err \"Oh!\") (Ok 5) == Ok 5\n\n or (Ok 4) (Err \"No!\") == Ok 4\n\n or (Err \"Oh!\") (Err \"No!\") == Err \"No!\"\n\nAs the last example line shows, the second error is returned if both\nresults are erroneous.\n\n","type":"Result.Result e a -> Result.Result e a -> Result.Result e a"},{"name":"orElse","comment":" Strict version of `orElseLazy` (and at the same time,\npiping-friendly version of `or`).\n\n orElse (Ok 4) (Ok 5) == Ok 5 -- crucial difference from `or`\n\n orElse (Err \"Oh!\") (Ok 5) == Ok 5\n\n orElse (Ok 4) (Err \"No!\") == Ok 4\n\n orElse (Err \"Oh!\") (Err \"No!\") == Err \"Oh!\" -- also different from `or`\n\nAlso:\n\n String.toInt \"Hello\"\n |> orElse (String.toInt \"42\")\n\n","type":"Result.Result e a -> Result.Result e a -> Result.Result e a"},{"name":"orElseLazy","comment":" Piping-friendly version of `orLazy`. The first argument will only\nbe evaluated if the second argument is an `Err`. Example use:\n\n String.toInt \"Hello\"\n |> orElseLazy (\\() -> String.toInt \"42\")\n\n","type":"(() -> Result.Result e a) -> Result.Result e a -> Result.Result e a"},{"name":"orLazy","comment":" Non-strict version of `or`. The second argument will only be\nevaluated if the first argument is an `Err`.\n","type":"Result.Result e a -> (() -> Result.Result e a) -> Result.Result e a"},{"name":"partition","comment":" Partition a list of Results into two lists of values (successes\nand failures), much as List.partition takes a predicate and splits\na list based on whether the predicate indicates success or failure.\n\n partition ( Ok 4, Err \"no\", Err \"hi\" ) == ( [ 4 ], [ \"no\", \"hi\" ] )\n\n partition ( Err 7.1, Ok 'k', Err 9.0, Ok 'p' ) == ( [ 'k', 'p' ], [ 7.1, 9.0 ] )\n\n","type":"List.List (Result.Result e a) -> ( List.List a, List.List e )"},{"name":"singleton","comment":" Create a `singleton` from a value to an `Result` with a `Ok`\nof the same type. Also known as `pure`. You can use the `Err`\nconstructor for a singleton of the `Err` variety.\n\n singleton 2 == Ok 2\n\n","type":"a -> Result.Result e a"},{"name":"toTask","comment":" Convert a `Result` to a `Task` that will fail or succeed immediately.\n\n toTask (Ok 4) == Task.succeed 4\n\n toTask (Err \"msg\") == Task.fail \"msg\"\n\nThis can be helpful when the value of a succeeding Task needs to be decoded, but\na failure to decode should result in a failing `Task`, not a succeeding Task\ncontaining a `Result.Err`:\n\nandThenDecode : (a -> Result x b) -> Task x a -> Task x b\nandThenDecode decode =\nTask.andThen (decode >> Result.Extra.toTask)\n\n","type":"Result.Result x a -> Task.Task x a"},{"name":"unpack","comment":" Convert a `Result e a` to a `b` by applying either the first\nfunction if the `Result` is an `Err` or the second function if the\n`Result` is `Ok`. Both of these functions must return the same type.\n","type":"(e -> b) -> (a -> b) -> Result.Result e a -> b"},{"name":"unwrap","comment":" Convert a `Result e a` to a `b` by applying a function if\nthe `Result` is `Ok` or using the provided default value if it\nis an `Err`.\n","type":"b -> (a -> b) -> Result.Result e a -> b"}],"binops":[]},{"name":"String.Extra","comment":" Additional functions for working with Strings\n\n\n## Change words casing\n\n@docs toSentenceCase, toTitleCase, decapitalize\n\n\n## Inflector functions\n\nFunctions borrowed from the Rails Inflector class\n\n@docs camelize, classify, underscored, dasherize, humanize\n\n\n## Replace and Splice\n\n@docs replaceSlice, insertAt, nonEmpty, nonBlank, removeAccents\n\n\n## Splitting\n\n@docs break, softBreak\n\n\n## Wrapping\n\n@docs wrap, wrapWith, softWrap, softWrapWith, quote, surround\n\n\n## Checks\n\n@docs isBlank, countOccurrences\n\n\n## Formatting\n\n@docs clean, unquote, unsurround, unindent, ellipsis, softEllipsis, ellipsisWith, stripTags, pluralize\n\n\n## Converting Lists\n\n@docs toSentence, toSentenceOxford\n\n\n## Finding\n\n@docs rightOf, leftOf, rightOfBack, leftOfBack\n\n\n## Converting UTF-32\n\n@docs toCodePoints, fromCodePoints\n\n","unions":[],"aliases":[],"values":[{"name":"break","comment":" Break a string into a list of strings of a specified maximum length.\n\n break 10 \"The quick brown fox\" == [ \"The quick \", \"brown fox\" ]\n\n break 2 \"\" == [ \"\" ]\n\n","type":"Basics.Int -> String.String -> List.List String.String"},{"name":"camelize","comment":" Convert an underscored or dasherized string to a camelized one.\n\n camelize \"-moz-transform\" == \"MozTransform\"\n\n","type":"String.String -> String.String"},{"name":"classify","comment":" Convert a string to a camelized string starting with an uppercase letter.\nAll non-word characters will be stripped out of the original string.\n\n classify \"some_class_name\" == \"SomeClassName\"\n\n classify \"myLittleCamel.class.name\" == \"MyLittleCamelClassName\"\n\n","type":"String.String -> String.String"},{"name":"clean","comment":" Trim the whitespace of both sides of the string and compress\nrepeated whitespace internally to a single whitespace char.\n\n clean \" The quick brown fox \" == \"The quick brown fox\"\n\n","type":"String.String -> String.String"},{"name":"countOccurrences","comment":" Return the number of occurrences of a substring in another string.\n\n countOccurrences \"Hello\" \"Hello World\" == 1\n\n countOccurrences \"o\" \"Hello World\" == 2\n\n","type":"String.String -> String.String -> Basics.Int"},{"name":"dasherize","comment":" Return a string joined by dashes after separating it by its uppercase characters.\nAny sequence of spaces or underscores will also be converted to a single dash.\nThe final string will be lowercased.\n\n dasherize \"SomeClassName\" --> \"some-class-name\"\n\n dasherize \"some_class_name\" --> \"some-class-name\"\n\n dasherize \"someClass name\" --> \"some-class-name\"\n\n","type":"String.String -> String.String"},{"name":"decapitalize","comment":" Decapitalize the first letter of a string.\n\n decapitalize \"This is a phrase\" == \"this is a phrase\"\n\n decapitalize \"Hello, World\" == \"hello, World\"\n\n","type":"String.String -> String.String"},{"name":"ellipsis","comment":" Truncate the string at the specified length if the string is\nlonger than the specified length, and replace the end of the truncated\nstring with `\"...\"`, such that the resulting string is of the\nspecified length.\n\nThe resulting string will have at most the specified length.\n\n ellipsis 5 \"Hello World\" == \"He...\"\n\n ellipsis 10 \"Hello World\" == \"Hello W...\"\n\n ellipsis 10 \"Hello\" == \"Hello\"\n\n ellipsis 8 \"Hello World\" == \"Hello...\"\n\n","type":"Basics.Int -> String.String -> String.String"},{"name":"ellipsisWith","comment":" Truncate the second string at the specified length if the string is\nlonger than the specified length, and replace the end of the truncated\nstring with the first string, such that the resulting string is of the\nspecified length.\n\nThe resulting string will have at most the specified length.\n\n ellipsisWith 5 \" ..\" \"Hello World\" == \"He ..\"\n\n ellipsisWith 10 \" ..\" \"Hello World\" == \"Hello W ..\"\n\n ellipsisWith 10 \" ..\" \"Hello\" == \"Hello\"\n\n ellipsisWith 8 \" ..\" \"Hello World\" == \"Hello ..\"\n\n","type":"Basics.Int -> String.String -> String.String -> String.String"},{"name":"fromCodePoints","comment":" Convert a list of UTF-32 code points into a string. Inverse of\n`toCodePoints`.\n\n fromCodePoints [ 97, 98, 99 ] == \"abc\"\n\n fromCodePoints [ 169, 167, 960 ] == \"©§π\"\n\n fromCodePoints [ 128169, 33 ] == \"💩!\"\n\n`fromCodePoints codePoints` is equivalent to:\n\n String.fromList (List.map Char.fromCode codePoints)\n\n","type":"List.List Basics.Int -> String.String"},{"name":"humanize","comment":" Convert an underscored, camelized, or dasherized string into one that can be\nread by humans. Also remove beginning and ending whitespace, and removes the\npostfix '\\_id'. The first character will be capitalized.\n\n humanize \"this_is_great\" == \"This is great\"\n humanize \"ThisIsGreat\" = \"This is great\"\n humanize \"this-is-great\" = \"This is great\"\n humanize \"author_id\" = \"Author\"\n\n","type":"String.String -> String.String"},{"name":"insertAt","comment":" Insert a substring at the specified index.\n\n insertAt \"world\" 6 \"Hello \" == \"Hello world\"\n\n","type":"String.String -> Basics.Int -> String.String -> String.String"},{"name":"isBlank","comment":" Test if a string is empty or only contains whitespace.\n\n isBlank \"\" == True\n\n isBlank \"\\n\" == True\n\n isBlank \" \" == True\n\n isBlank \" a\" == False\n\n","type":"String.String -> Basics.Bool"},{"name":"leftOf","comment":" Search a string from left to right for a pattern and return a substring\nconsisting of the characters in the string that are to the left of the pattern.\n\n leftOf \"_\" \"This_is_a_test_string\" == \"This\"\n\n","type":"String.String -> String.String -> String.String"},{"name":"leftOfBack","comment":" Search a string from right to left for a pattern and return a substring\nconsisting of the characters in the string that are to the left of the pattern.\n\n leftOfBack \"_\" \"This_is_a_test_string\" == \"This_is_a_test\"\n\n","type":"String.String -> String.String -> String.String"},{"name":"nonBlank","comment":" Convert a string to a Nothing when blank.\n\n nonBlank \"\" == Nothing\n\n nonBlank \" \" == Nothing\n\n nonBlank \"Hello world\" == Just \"Hello world\"\n\n","type":"String.String -> Maybe.Maybe String.String"},{"name":"nonEmpty","comment":" Convert a string to a Nothing when empty.\n\n nonEmpty \"\" == Nothing\n\n nonEmpty \"Hello world\" == Just \"Hello world\"\n\n","type":"String.String -> Maybe.Maybe String.String"},{"name":"pluralize","comment":" Given a number, a singular string, and a plural string, return the number\nfollowed by a space, followed by either the singular string if the number was 1,\nor the plural string otherwise.\n\n pluralize \"elf\" \"elves\" 2 == \"2 elves\"\n\n pluralize \"elf\" \"elves\" 1 == \"1 elf\"\n\n pluralize \"elf\" \"elves\" 0 == \"0 elves\"\n\n","type":"String.String -> String.String -> Basics.Int -> String.String"},{"name":"quote","comment":" Add quotes to a string.\n\n quote \"foo\" == \"\\\"foo\\\"\"\n\n","type":"String.String -> String.String"},{"name":"removeAccents","comment":" Remove accents from string.\n\n removeAccents \"andré\" == \"andre\"\n\n removeAccents \"Atenção\" == \"Atencao\"\n\n","type":"String.String -> String.String"},{"name":"replaceSlice","comment":" Replace text within a portion of a string given a substitution\nstring, a start index and an end index. The substitution includes the character\nat the start index but not the one at the end index.\n\n replaceSlice \"Sue\" 4 7 \"Hi, Bob\" == \"Hi, Sue\"\n\n replaceSlice \"elephants\" 0 6 \"snakes on a plane!\" == \"elephants on a plane!\"\n\n replaceSlice \"under\" 7 9 \"snakes on a plane!\" == \"snakes under a plane!\"\n\n","type":"String.String -> Basics.Int -> Basics.Int -> String.String -> String.String"},{"name":"rightOf","comment":" Search a string from left to right for a pattern and return a substring\nconsisting of the characters in the string that are to the right of the pattern.\n\n rightOf \"_\" \"This_is_a_test_string\" == \"is_a_test_string\"\n\n","type":"String.String -> String.String -> String.String"},{"name":"rightOfBack","comment":" Search a string from right to left for a pattern and return a substring\nconsisting of the characters in the string that are to the right of the pattern.\n\n rightOfBack \"_\" \"This_is_a_test_string\" == \"string\"\n\n","type":"String.String -> String.String -> String.String"},{"name":"softBreak","comment":" Break a string into a list of strings of a specified maximum length,\nwithout truncating words.\n\n softBreak 6 \"The quick brown fox\" == [ \"The quick\", \" brown\", \" fox\" ]\n\n","type":"Basics.Int -> String.String -> List.List String.String"},{"name":"softEllipsis","comment":" Truncate the string at the last complete word less than or equal to\nthe specified length and append `\"...\"`. When the specified length is\nless than the length of the first word, the ellipsis is appended to the\nfirst word. When the specified length is greater than or equal to the\nlength of the string, an identical string is returned.\n\nIn contrast to `ellipsis`, this function will not produce incomplete\nwords, and the resulting string can exceed the specified length. In\naddition, it removes trailing whitespace and punctuation characters at\nthe end of the truncated string.\n\n softEllipsis 1 \"Hello, World\" == \"Hello...\"\n\n softEllipsis 5 \"Hello, World\" == \"Hello...\"\n\n softEllipsis 6 \"Hello, World\" == \"Hello...\"\n\n softEllipsis 15 \"Hello, cruel world\" == \"Hello, cruel...\"\n\n softEllipsis 10 \"Hello\" == \"Hello\"\n\n","type":"Basics.Int -> String.String -> String.String"},{"name":"softWrap","comment":" Chop a given string into parts of a given width without breaking words apart,\nand then separate them using a new line.\n\n softWrap 7 \"My very long text\" === \"My very\\nlong text\"\n\n softWrap 3 \"Hello World\" === \"Hello \\nWorld\"\n\n softWrap 100 \"Too short\" === \"Too short\"\n\n","type":"Basics.Int -> String.String -> String.String"},{"name":"softWrapWith","comment":" Chop a given string into parts of a given width without breaking words apart,\nand then separate them using the given separator.\n\n softWrapWith 7 \"...\" \"My very long text\" === \"My very...long text\"\n\n softWrapWith 3 \"\\n\" \"Hello World\" === \"Hello \\nWorld\"\n\n softWrapWith 100 \"\\t\" \"Too short\" === \"Too short\"\n\n","type":"Basics.Int -> String.String -> String.String -> String.String"},{"name":"stripTags","comment":" Remove all HTML tags from the string, preserving the text inside them.\n\n stripTags \"a link\" == \"a link\"\n stripTags \" == \"alert('hello world!')\"\n\n","type":"String.String -> String.String"},{"name":"surround","comment":" Surround a string with another string.\n\n surround \"bar\" \"foo\" == \"barfoobar\"\n\n","type":"String.String -> String.String -> String.String"},{"name":"toCodePoints","comment":" Convert a string into a list of UTF-32 code points.\n\n toCodePoints \"abc\" == [ 97, 98, 99 ]\n\n toCodePoints \"©§π\" == [ 169, 167, 960 ]\n\n toCodePoints \"💩!\" == [ 128169, 33 ]\n\nNote that code points do not necessarily correspond to logical/visual\ncharacters, since it is possible for things like accented characters to be\nrepresented as two separate UTF-32 code points (a base character and a\ncombining accent).\n\n`toCodePoints string` is equivalent to:\n\n List.map Char.toCode (String.toList string)\n\n","type":"String.String -> List.List Basics.Int"},{"name":"toSentence","comment":" Convert a list of strings into a human-readable list.\n\n toSentence [] == \"\"\n\n toSentence [ \"lions\" ] == \"lions\"\n\n toSentence [ \"lions\", \"tigers\" ] == \"lions and tigers\"\n\n toSentence [ \"lions\", \"tigers\", \"bears\" ] == \"lions, tigers and bears\"\n\n","type":"List.List String.String -> String.String"},{"name":"toSentenceCase","comment":" Capitalize the first letter of a string.\n\n toSentenceCase \"this is a phrase\" == \"This is a phrase\"\n\n toSentenceCase \"hello, world\" == \"Hello, world\"\n\n","type":"String.String -> String.String"},{"name":"toSentenceOxford","comment":" Convert a list of strings into a human-readable list using an oxford comma.\n\n toSentenceOxford [] == \"\"\n\n toSentenceOxford [ \"lions\" ] == \"lions\"\n\n toSentenceOxford [ \"lions\", \"tigers\" ] == \"lions and tigers\"\n\n toSentenceOxford [ \"lions\", \"tigers\", \"bears\" ] == \"lions, tigers, and bears\"\n\n","type":"List.List String.String -> String.String"},{"name":"toTitleCase","comment":" Capitalize the first character of each word in a string.\n\n toTitleCase \"this is a phrase\" == \"This Is A Phrase\"\n\n toTitleCase \"hello, world\" == \"Hello, World\"\n\n","type":"String.String -> String.String"},{"name":"underscored","comment":" Return a string joined by underscores after separating it by its uppercase characters.\nAny sequence of spaces or dashes will also be converted to a single underscore.\nThe final string will be lowercased.\n\n underscored \"SomeClassName\" == \"some_class_name\"\n underscored \"some-class-name\" == \"some_class_name\"\n underscored \"SomeClass name\" == \"some_class_name\n\n","type":"String.String -> String.String"},{"name":"unindent","comment":" Remove the shortest sequence of leading spaces or tabs on each line\nof the string, so that at least one of the lines will not have any\nleading spaces nor tabs and the rest of the lines will have the same\namount of indentation removed.\n\n unindent \" Hello\\n World \" == \"Hello\\n World\"\n\n unindent \"\\t\\tHello\\n\\t\\t\\t\\tWorld\" == \"Hello\\n\\t\\tWorld\"\n\n","type":"String.String -> String.String"},{"name":"unquote","comment":" Remove quotes that surround a string.\n\n unquote \"\\\"foo\\\"\" == \"foo\"\n\n unquote \"\\\"foo\\\"bar\\\"\"\n\n","type":"String.String -> String.String"},{"name":"unsurround","comment":" Remove surrounding strings from another string.\n\n unsurround \"foo\" \"foobarfoo\" == \"bar\"\n\n","type":"String.String -> String.String -> String.String"},{"name":"wrap","comment":" Chop a given string into parts of a given width, separating them with a\nnew line.\n\n wrap 7 \"My very long text\" === \"My very\\nlong te\\nxt\"\n\n wrap 100 \"Too short\" === \"Too short\"\n\n","type":"Basics.Int -> String.String -> String.String"},{"name":"wrapWith","comment":" Separate a string into parts of a given width, using a given separator.\n\nLook at `wrap` if you just want to wrap using newlines.\n\n wrapWith 7 \"\\n\" \"My very long text\" === \"My very\\nlong text\"\n\n wrapWith 100 \"\\n\" \"Too short\" === \"Too short\"\n\n","type":"Basics.Int -> String.String -> String.String -> String.String"}],"binops":[]},{"name":"Tuple.Extra","comment":"\n\n@docs Tuple\n\n\n## Paring\n\n@docs pairWith, from\n\n\n## Manipulating\n\n@docs apply, flip, join, joinBy, sum, product, sort, sortBy, sortWith\n\n\n## Mapping\n\n@docs map\n\n\n## Maybes\n\n@docs sequenceMaybe, sequenceFirstMaybe, sequenceSecondMaybe\n\n","unions":[],"aliases":[{"name":"Tuple","comment":" By type aliasing tuples into a \"normal\" type, we remove the (small) effort\nrequired in reading types and signatures that have tuples in. I've found this\nis most beneficial when a tuple is nested inside another type. Visually, the\nTuple type is now no different to List, Maybe, or Result.\n\nFor example, this:\n\n List (Maybe ( String, Int ))\n\nbecomes:\n\n List (Maybe (Tuple String Int))\n\n","args":["a","b"],"type":"( a, b )"}],"values":[{"name":"apply","comment":" Given a function that takes two arguments, apply that function to the two\nvalues contained in a tuple.\n\n Tuple.apply (+) ( 1, 2 )\n == 3\n\n","type":"(a -> b -> c) -> Tuple.Extra.Tuple a b -> c"},{"name":"flip","comment":" Flip the two values contained in a tuple.\n","type":"Tuple.Extra.Tuple a b -> Tuple.Extra.Tuple b a"},{"name":"from","comment":" Occasionally you might want to create a Tuple from a single value. This does\njust that.\n\n Tuple.from 1\n == ( 1, 1 )\n\n","type":"a -> Tuple.Extra.Tuple a a"},{"name":"join","comment":" Similar to String.join but for tuples instead of lists. Given some separator\nstring, join together two strings in a tuple.\n\n Tuple.join \" \" ( \"Hello\", \"world\" )\n == \"Hello world\"\n\n","type":"appendable -> Tuple.Extra.Tuple appendable appendable -> appendable"},{"name":"joinBy","comment":" Works just like join, but first converts the values of the tuple to strings.\nThese means the function works with any type of tuple.\n\n Tuple.joinBy String.fromInt suitToString \" of \" ( 7, Club )\n == \"Seven of Clubs\"\n\n","type":"(a -> appendable) -> (b -> appendable) -> appendable -> Tuple.Extra.Tuple a b -> appendable"},{"name":"map","comment":" Apply a function to both values contained in a tuple. This might also be\nknown as `mapBothWith` or `bimap`.\n\n Tuple.map negate ( -3, 10 )\n == ( 3, -10 )\n\n","type":"(a -> b) -> Tuple.Extra.Tuple a a -> Tuple.Extra.Tuple b b"},{"name":"pairWith","comment":" In certain situations, this proves more \"pipe friendly\" than the standard\n`Tuple.pair`. Fits nicely in your `update` function.\n\n { model | count = model.count + 1 }\n |> Tuple.pairWith Cmd.none\n\n","type":"b -> a -> Tuple.Extra.Tuple a b"},{"name":"product","comment":" Similar to List.sum but for tuples instead of lists. Multiplies together two\nnumbers contained in a tuple\n\n Tuple.product ( 1, 2 )\n == 2\n\n","type":"Tuple.Extra.Tuple number number -> number"},{"name":"sequenceFirstMaybe","comment":" Similar to `sequenceMaybe` but only looks at the first value in a tuple\nto check for nothingness.\n\n Tuple.sequenceFirstMaybe ( Just 10, \"Cat\" )\n == Maybe ( 10, \"Cat\" )\n\n","type":"Tuple.Extra.Tuple (Maybe.Maybe a) b -> Maybe.Maybe (Tuple.Extra.Tuple a b)"},{"name":"sequenceMaybe","comment":" Occasionally you might find yourself in a situation where both values\ncontained in a tuple are `Maybe`s. Sometimes it makes more sense to take those\nvalues and make the tuple a `Maybe` instead.\n\n Tuple.sequenceMaybe ( Just 10, Nothing )\n == Nothing\n\n Tuple.sequenceMaybe ( Just 10, Just \"Cat\" )\n == Maybe ( 10, \"Cat\" )\n\n","type":"Tuple.Extra.Tuple (Maybe.Maybe a) (Maybe.Maybe b) -> Maybe.Maybe (Tuple.Extra.Tuple a b)"},{"name":"sequenceSecondMaybe","comment":" Similar to `sequenceMaybe` but only looks at the first value in a tuple\nto check for nothingness.\n\n Tuple.sequenceSecondMaybe ( 10, Just \"Cat\" )\n == Maybe ( 10, \"Cat\" )\n\n","type":"Tuple.Extra.Tuple a (Maybe.Maybe b) -> Maybe.Maybe (Tuple.Extra.Tuple a b)"},{"name":"sort","comment":" Similar to List.sort but for tuples instead of lists. Sort values contained\nin a tuple from lowest to highest\n\n Tuple.sort ( 2, 1 )\n == ( 1, 2 )\n\n","type":"Tuple.Extra.Tuple comparable comparable -> Tuple.Extra.Tuple comparable comparable"},{"name":"sortBy","comment":" Similar to List.sortBy but for tuples instead of lists. Sort values\ncontained in a tuple by first converting both values to a `comparable`. The\nvalues are sorted lowest to highest\n\n Tuple.sortBy String.length ( \"mouse\", \"cat\" )\n == ( \"cat\", \"mouse\" )\n\n","type":"(a -> comparable) -> Tuple.Extra.Tuple a a -> Tuple.Extra.Tuple a a"},{"name":"sortWith","comment":" Similar to List.sortWith but for tuples instead of lists. Instead of\nconverting values contained in a tuple to `comparable`s, instead supply a\nfunction that will produce an `Order` directly.\n\n Tuple.sortWith Basics.compare ( 2, 1 )\n == Tuple.sort ( 2, 1 )\n == ( 1, 2 )\n\n","type":"(a -> a -> Basics.Order) -> Tuple.Extra.Tuple a a -> Tuple.Extra.Tuple a a"},{"name":"sum","comment":" Similar to List.sum but for tuples instead of lists. Adds together two\nnumbers contained in a tuple.\n\n Tuple.sum ( 1, 2 )\n == 3\n\n","type":"Tuple.Extra.Tuple number number -> number"}],"binops":[]}] \ No newline at end of file diff --git a/elm.json b/elm.json index 8ae7c9c..161f594 100644 --- a/elm.json +++ b/elm.json @@ -10,6 +10,7 @@ "Char.Extra", "Cmd.Extra", "Dict.Extra", + "Float.Extra", "List.Extra", "Maybe.Extra", "Order.Extra", diff --git a/review/src/ReviewConfig.elm b/review/src/ReviewConfig.elm index d6ce71e..17a0e83 100644 --- a/review/src/ReviewConfig.elm +++ b/review/src/ReviewConfig.elm @@ -65,6 +65,6 @@ config = , NoUnused.Parameters.rule , NoUnused.Patterns.rule , NoUnused.Variables.rule - , Simplify.rule Simplify.defaults + , Simplify.rule (Simplify.expectNaN Simplify.defaults) ] |> List.map (Rule.ignoreErrorsForDirectories [ "tests/VerifyExamples" ]) diff --git a/src/Float/Extra.elm b/src/Float/Extra.elm new file mode 100644 index 0000000..4d4817a --- /dev/null +++ b/src/Float/Extra.elm @@ -0,0 +1,368 @@ +module Float.Extra exposing + ( aboutEqual + , toFixedDecimalPlaces, toFixedSignificantDigits, boundaryValuesAsUnicode + , range + ) + +{-| + + +# Equality + +@docs aboutEqual + + +# Formatting Floats + +@docs toFixedDecimalPlaces, toFixedSignificantDigits, boundaryValuesAsUnicode + + +# Ranges + +@docs range + +-} + +import Bitwise + + + +-- toFixedDecimalDigits implementation + + +zeroes : Float -> String +zeroes v = + String.repeat (floor v) "0" + + +adjustDecimalPlace : Float -> Float -> Float +adjustDecimalPlace x magnitude = + if magnitude < 0 then + x * 10 ^ -magnitude + + else + x / 10 ^ magnitude + + +{-| This ugly code is a port of the Intl API +-} +toRawPrecision : Float -> Int -> Int -> String +toRawPrecision x minPrecision maxPrecision = + -- IGNORE TCO - there is only so much precision to be had in JS numbers + let + p = + toFloat maxPrecision + + defaultCase _ = + let + e_ = + toFloat <| floor <| logBase 10 <| abs x + + decimalPlaceOffset = + e_ - p + 1 + + n = + round (adjustDecimalPlace x decimalPlaceOffset) + in + if adjustDecimalPlace (toFloat n) (p - 1) >= 10 then + ( String.fromInt (n // 10), e_ + 1 ) + + else + ( String.fromInt n, e_ ) + + ( m, ex ) = + if x == 0 then + ( zeroes p, 0 ) + + else + case String.split "e" (String.fromFloat x) of + [ xToStringMantissa, xToStringExponent ] -> + case String.toFloat xToStringExponent of + Just xExponent -> + let + xToStringMantissaWithoutDecimalPoint = + String.replace "." "" xToStringMantissa + + len = + toFloat (String.length xToStringMantissaWithoutDecimalPoint) + in + if len <= p then + ( xToStringMantissaWithoutDecimalPoint ++ zeroes (p - len), xExponent ) + + else + ( xToStringMantissa + |> String.toFloat + |> Maybe.map (\v -> toRawPrecision v minPrecision maxPrecision ++ "e" ++ xToStringExponent) + |> Maybe.withDefault xToStringMantissaWithoutDecimalPoint + , --hack + p - 1 + ) + + _ -> + defaultCase () + + _ -> + defaultCase () + in + if ex >= p then + m ++ zeroes (ex - p + 1) + + else if ex == p - 1 then + m + + else + let + m2 = + if ex >= 0 then + String.slice 0 (floor (ex + 1)) m ++ "." ++ String.dropLeft (floor (ex + 1)) m + + else if ex < 0 then + "0." ++ zeroes -(ex + 1) ++ m + + else + m + in + if String.contains "." m2 && maxPrecision > minPrecision then + let + doCut toCut lst = + if toCut > 0 then + case lst of + '0' :: rst -> + doCut (toCut - 1) rst + + '.' :: rst -> + List.reverse rst + + _ -> + List.reverse lst + + else if List.head lst == Just '.' then + List.tail lst + |> Maybe.withDefault [] + |> List.reverse + + else + List.reverse lst + in + String.toList m2 + |> List.reverse + |> doCut (maxPrecision - minPrecision) + |> String.fromList + + else + m2 + + +sign : Float -> String +sign x = + if x >= 0 then + "" + + else + "-" + + +{-| Fix a float value represented as a string to a certain number of significant digits. + + Float.Extra.toFixedSignificantDigits 2 1.435 --> "1.4" + + Float.Extra.toFixedSignificantDigits 2 545435 --> "550000" + + Float.Extra.toFixedSignificantDigits 2 0.0039 --> "0.0039" + +-} +toFixedSignificantDigits : Int -> Float -> String +toFixedSignificantDigits significantDigits value = + if isNaN value then + "NaN" + + else if isInfinite value then + sign value ++ "Infinity" + + else + sign value ++ toRawPrecision (abs value) 1 (max 1 significantDigits) + + + +-- toFixedDecimalPlaces implementation + + +{-| Fix a float value represented to a certain number of decimal places as a string. + + Float.Extra.toFixedDecimalPlaces 3 0.0326232 --> "0.033" + +-} +toFixedDecimalPlaces : Int -> Float -> String +toFixedDecimalPlaces decimalPlaces value = + let + padString s = + case String.split "." s of + [ v1, v2 ] -> + v1 ++ "." ++ String.padRight decimalPlaces '0' v2 + + [ v1 ] -> + v1 ++ "." ++ String.repeat decimalPlaces "0" + + _ -> + s + in + if isNaN value then + "NaN" + + else if isInfinite value then + sign value ++ "Infinity" + + else if decimalPlaces <= 0 then + roundAsFloat decimalPlaces value + |> String.fromFloat + + else + value + |> roundToDecimal decimalPlaces + |> String.fromFloat + |> padString + + +roundAsFloat : Int -> Float -> Float +roundAsFloat places strNum = + if places < 0 then + strNum + + else + roundToDecimal places strNum + + +roundToDecimal : Int -> Float -> Float +roundToDecimal places = + if places < 0 then + identity + + else + let + exp : Float + exp = + 10.0 ^ toFloat places + + multiplyByExp : Float -> Float + multiplyByExp = + (*) exp + + divByExp : Float -> Float + divByExp v = + v / exp + in + multiplyByExp >> round >> toFloat >> divByExp + + + +-- boundaryValuesAsUnicode + + +{-| When showing Float values to users, we generally don't particularly want them to see programmer-y values like +`NaN` or `Infinity`. This function wraps a number formatting routine, but replaces those values with unicode symbols: + + format : Float -> String + format = + Float.Extra.toFixedSignificantDigits 3 + |> Float.Extra.boundaryValuesAsUnicode + + format (0 / 0) --> "∅" + format (1 / 0) --> "∞" + format (-1 / 0) --> "-∞" + format (1 / 3) -> "0.333" + +Of course using this is unsuitable for when you want the numbers to be machine readable. + +-} +boundaryValuesAsUnicode : (Float -> String) -> Float -> String +boundaryValuesAsUnicode formatter value = + if isNaN value then + "∅" + + else if isInfinite value then + sign value ++ "∞" + + else + formatter value + + + +-- aboutEqual + + +{-| Comparing Floats with `==` is usually wrong, unless you basically care for reference equality, since floating point +numbers often have small precision drift. + + 0.1 + 0.2 == 0.3 --> False + +This function implements an approximation where we are asking - are these values close enough that we can consider their difference to be +due to floating point drift rather than a result of meaningful difference in calculation? + + (0.1 + 0.2) |> Float.Extra.aboutEqual 0.3 --> True + +Note: this is unlikely to be appropriate if you are performing computations much smaller than one. + + (0.00001 + 0.00002) |> Float.Extra.aboutEqual 0.00003 --> True + +This value handles Infinity and NaN like so: + + (1 / 0) |> Float.Extra.aboutEqual (100 / 0) --> True + + (0 / 0) |> Float.Extra.aboutEqual (0 / 0) --> False + +-} +aboutEqual : Float -> Float -> Bool +aboutEqual a b = + if isInfinite a then + isInfinite b + + else if isInfinite b then + False + + else + abs (a - b) <= 1.0e-5 + 1.0e-8 * abs a + + + +-- Range + + +{-| Returns a List containing an arithmetic progression, similar to the Python +built-in range. + +Takes a `start`, `stop` and `step` argument. The stop value is exclusive; it is not +included in the result. If `step` is positive, the last element is the largest +`start + i * step` less than `stop`; if `step` is negative, the last element is +the smallest `start + i * step` greater than `stop`. If the returned list would +contain an infinite number of values, an empty range is returned. + +The arguments are not required to be whole numbers; however, the results are more +predictable if they are. + +Differences from [List.range from the standard library](https://package.elm-lang.org/packages/elm/core/latest/List#range): + + - `List.range` is inclusive, meaning that the stop value will be included in the result + - `List.range` supports `Int`, whereas this uses `Float` + - `List.range` supports only increasing intervals (i.e. `List.range 3 1 == []` vs. `range 3 1 -1 == [3, 2]`) + - `List.range` doesn't allow for specifying the step value + +-} +range : Float -> Float -> Float -> List Float +range start stop step = + let + n = + (stop - start) + / step + |> ceiling + -- get rid of NaN + |> Bitwise.or 0 + |> max 0 + + helper i list = + if i >= 0 then + helper (i - 1) (start + step * toFloat i :: list) + + else + list + in + helper (n - 1) [] diff --git a/tests/FloatTests.elm b/tests/FloatTests.elm new file mode 100644 index 0000000..3a60dc2 --- /dev/null +++ b/tests/FloatTests.elm @@ -0,0 +1,279 @@ +module FloatTests exposing (testAboutEqual, testBoundaryValuesAsUnicode, testRange, testToFixedDecimalPlaces, testToFixedSignificantDigits) + +import Expect +import Float.Extra exposing (aboutEqual) +import Fuzz +import List.Extra exposing (Step(..)) +import Test exposing (Test, describe, fuzz, fuzz2, test) + + +testToFixedDecimalPlaces : Test +testToFixedDecimalPlaces = + describe "String.toFixedDecimalPlaces should take a string representation of a float value and round it to a fixed number of decimal places." + [ test "Should pad with zeroes to required decimal places" <| + \_ -> + Float.Extra.toFixedDecimalPlaces 2 56 + |> Expect.equal "56.00" + , test "Should pad zero values to required decimal places" <| + \_ -> + Float.Extra.toFixedDecimalPlaces 3 0 + |> Expect.equal "0.000" + , test "Should round to integer with 0 decimal places" <| + \_ -> + Float.Extra.toFixedDecimalPlaces 0 4.92 + |> Expect.equal "5" + , test "Should remove decimal places and round up" <| + \_ -> + Float.Extra.toFixedDecimalPlaces 2 123.345 + |> Expect.equal "123.35" + , test "Should pad numbers less than 1 to required decimal places" <| + \_ -> + Float.Extra.toFixedDecimalPlaces 2 0.6 + |> Expect.equal "0.60" + , test "Should maintain decimal places if no rounding is required" <| + \_ -> + Float.Extra.toFixedDecimalPlaces 2 0.06 + |> Expect.equal "0.06" + , test "Should remove decimal places and round for numbers between 0 and 1" <| + \_ -> + Float.Extra.toFixedDecimalPlaces 2 0.006 + |> Expect.equal "0.01" + , test "Should round to 0 with padding for numbers between 0 and 1 that round down" <| + \_ -> + Float.Extra.toFixedDecimalPlaces 2 0.003 + |> Expect.equal "0.00" + , test "handles NaN" <| + \_ -> + Float.Extra.toFixedDecimalPlaces 2 (0 / 0) + |> Expect.equal "NaN" + , test "handles Infinity" <| + \_ -> + Float.Extra.toFixedDecimalPlaces 2 (1 / 0) + |> Expect.equal "Infinity" + , test "handles -Infinity" <| + \_ -> + Float.Extra.toFixedDecimalPlaces 2 (-1 / 0) + |> Expect.equal "-Infinity" + ] + + +testToFixedSignificantDigits : Test +testToFixedSignificantDigits = + describe "String.toFixedSignificantDigits should take a string representation of a float value and round it to a fixed number of significant digits." + [ test "should round down to required digits" <| + \_ -> + Float.Extra.toFixedSignificantDigits 2 56.1 + |> Expect.equal "56" + , test "should round up to required digits" <| + \_ -> + Float.Extra.toFixedSignificantDigits 2 56.8 + |> Expect.equal "57" + , test "handles negative values" <| + \_ -> + Float.Extra.toFixedSignificantDigits 2 -56.8 + |> Expect.equal "-57" + , fuzz2 Fuzz.niceFloat (Fuzz.intRange 1 20) "produces at most n significant digits" <| + \num digits -> + Float.Extra.toFixedSignificantDigits digits num + |> String.toList + |> List.Extra.stoppableFoldl + (\d total -> + if d == '1' || d == '2' || d == '3' || d == '4' || d == '5' || d == '6' || d == '7' || d == '8' || d == '9' then + Continue (total + 1) + + else if d == '0' || d == '.' || d == '-' then + Continue total + + else if d == 'e' then + Stop total + + else + Stop 999999999 + ) + 0 + |> Expect.atMost digits + , fuzz2 Fuzz.niceFloat (Fuzz.intRange 1 20) "more or less preserves the value" <| + \num digits -> + num + |> Float.Extra.toFixedSignificantDigits digits + |> String.toFloat + |> Maybe.map (Expect.within (Expect.Relative (1 / toFloat digits)) num) + |> Maybe.withDefault (Expect.fail "Converting output to float failed") + , test "negative digits just means 1" <| + \_ -> + Float.Extra.toFixedSignificantDigits -1 4.15 + |> Expect.equal "4" + , test "tricky rounding" <| + \_ -> + Float.Extra.toFixedSignificantDigits 3 80.99999999999967 + |> Expect.equal "81" + , test "handles very small numbers" <| + \_ -> + Float.Extra.toFixedSignificantDigits 3 9.208633855450898e-12 + |> Expect.equal "9.21e-12" + , test "handles NaN" <| + \_ -> + Float.Extra.toFixedSignificantDigits 2 (0 / 0) + |> Expect.equal "NaN" + , test "handles Infinity" <| + \_ -> + Float.Extra.toFixedSignificantDigits 2 (1 / 0) + |> Expect.equal "Infinity" + , test "handles -Infinity" <| + \_ -> + Float.Extra.toFixedSignificantDigits 2 (-1 / 0) + |> Expect.equal "-Infinity" + ] + + +testBoundaryValuesAsUnicode : Test +testBoundaryValuesAsUnicode = + describe "boundaryValuesAsUnicode fixes infinity and NaN to unicode" + [ test "handles NaN" <| + \_ -> + (0 / 0) + |> Float.Extra.boundaryValuesAsUnicode (Float.Extra.toFixedSignificantDigits 2) + |> Expect.equal "∅" + , test "handles Infinity" <| + \_ -> + (1 / 0) + |> Float.Extra.boundaryValuesAsUnicode (Float.Extra.toFixedSignificantDigits 2) + |> Expect.equal "∞" + , test "handles -Infinity" <| + \_ -> + (-1 / 0) + |> Float.Extra.boundaryValuesAsUnicode (Float.Extra.toFixedSignificantDigits 2) + |> Expect.equal "-∞" + , fuzz Fuzz.niceFloat "works like formatter" <| + \v -> + v + |> Float.Extra.boundaryValuesAsUnicode (Float.Extra.toFixedSignificantDigits 2) + |> Expect.equal (Float.Extra.toFixedSignificantDigits 2 v) + ] + + +testAboutEqual : Test +testAboutEqual = + fuzz Fuzz.niceFloat "makes numbers about equal even after some operations" <| + \a -> + ((a + 10 + a - 10 - a) * 2 / 2) + |> aboutEqual a + |> Expect.equal True + + +testRange : Test +testRange = + describe "range start stop step" + [ test "returns [start, start + step, start + 2 * step, … stop - step]" <| + \() -> + expectAll + [ Float.Extra.range 0 5 1 + |> Expect.equal [ 0, 1, 2, 3, 4 ] + , Float.Extra.range 0 5 2 + |> Expect.equal [ 0, 2, 4 ] + , Float.Extra.range 2 5 2 + |> Expect.equal [ 2, 4 ] + , Float.Extra.range -1 3 2 + |> Expect.equal [ -1, 1 ] + ] + , test "allows a negative step" <| + \() -> + expectAll + [ Float.Extra.range 5 0 -1 + |> Expect.equal [ 5, 4, 3, 2, 1 ] + , Float.Extra.range 5 0 -2 + |> Expect.equal [ 5, 3, 1 ] + , Float.Extra.range 5 2 -2 + |> Expect.equal [ 5, 3 ] + , Float.Extra.range 3 -1 -2 + |> Expect.equal [ 3, 1 ] + ] + , test "returns an empty array if start >= stop and step > 0" <| + \() -> + expectAll + [ Float.Extra.range 5 5 2 + |> Expect.equal [] + , Float.Extra.range 6 5 2 + |> Expect.equal [] + , Float.Extra.range 10 10 1 + |> Expect.equal [] + , Float.Extra.range 10 10 0.5 + |> Expect.equal [] + , Float.Extra.range 0 0 1 + |> Expect.equal [] + , Float.Extra.range 0 0 0.5 + |> Expect.equal [] + , Float.Extra.range 20 10 2 + |> Expect.equal [] + , Float.Extra.range 20 10 1 + |> Expect.equal [] + , Float.Extra.range 20 10 0.5 + |> Expect.equal [] + ] + , test "returns an empty array if start >= stop and step < 0" <| + \() -> + expectAll + [ Float.Extra.range 5 5 -2 + |> Expect.equal [] + , Float.Extra.range 5 6 -2 + |> Expect.equal [] + , Float.Extra.range 10 10 -1 + |> Expect.equal [] + , Float.Extra.range 10 10 -0.5 + |> Expect.equal [] + , Float.Extra.range 0 0 -1 + |> Expect.equal [] + , Float.Extra.range 0 0 -0.5 + |> Expect.equal [] + , Float.Extra.range 10 20 -2 + |> Expect.equal [] + , Float.Extra.range 10 20 -1 + |> Expect.equal [] + , Float.Extra.range 10 20 -0.5 + |> Expect.equal [] + ] + , test "returns an empty array if step is zero" <| + \() -> + Float.Extra.range 0 5 0 + |> Expect.equal [] + , fuzz2 (Fuzz.intRange -1000 1000) (Fuzz.intRange -1000 1000) "behaves the same as List.range for ints" <| + \a b -> + Float.Extra.range (toFloat (min a b)) (toFloat (max a b)) 1 + |> List.map round + -- account for List.range being inclusive + |> (\y -> List.append y [ max a b ]) + |> Expect.equal (List.range (min a b) (max a b)) + , test "returns exactly [start + step * i, …] for fractional steps" <| + \() -> + expectAll + [ Float.Extra.range 0 0.5 0.1 + |> Expect.equal [ 0, 0.1, 0.1 * 2, 0.1 * 3, 0.1 * 4 ] + , Float.Extra.range 0.5 0 -0.1 + |> Expect.equal [ 0.5, 0.5 - 0.1, 0.5 - 0.1 * 2, 0.5 - 0.1 * 3, 0.5 - 0.1 * 4 ] + , Float.Extra.range -2 -1.2 0.1 + |> Expect.equal [ -2, -2 + 0.1, -2 + 0.1 * 2, -2 + 0.1 * 3, -2 + 0.1 * 4, -2 + 0.1 * 5, -2 + 0.1 * 6, -2 + 0.1 * 7 ] + , Float.Extra.range -1.2 -2 -0.1 + |> Expect.equal [ -1.2, -1.2 - 0.1, -1.2 - 0.1 * 2, -1.2 - 0.1 * 3, -1.2 - 0.1 * 4, -1.2 - 0.1 * 5, -1.2 - 0.1 * 6, -1.2 - 0.1 * 7 ] + ] + , test "returns exactly [start + step * i, …] for very small fractional steps" <| + \() -> + expectAll + [ Float.Extra.range 2.1e-31 5.0e-31 1.1e-31 + |> Expect.equal [ 2.1e-31, 2.1e-31 + 1.1e-31, 2.1e-31 + 1.1e-31 * 2 ] + , Float.Extra.range 5.0e-31 2.1e-31 -1.1e-31 + |> Expect.equal [ 5.0e-31, 5.0e-31 - 1.1e-31, 5.0e-31 - 1.1e-31 * 2 ] + ] + , test "returns exactly [start + step * i, …] for very large fractional steps" <| + \() -> + expectAll + [ Float.Extra.range 1.0e300 2.0e300 3.0e299 + |> Expect.equal [ 1.0e300, 1.0e300 + 3.0e299, 1.0e300 + 3.0e299 * 2, 1.0e300 + 3.0e299 * 3 ] + , Float.Extra.range 2.0e300 1.0e300 -3.0e299 + |> Expect.equal [ 2.0e300, 2.0e300 - 3.0e299, 2.0e300 - 3.0e299 * 2, 2.0e300 - 3.0e299 * 3 ] + ] + ] + + +expectAll : List Expect.Expectation -> Expect.Expectation +expectAll expectations = + Expect.all (List.map always expectations) () diff --git a/tests/elm-verify-examples.json b/tests/elm-verify-examples.json index c59b21a..f8f4f14 100644 --- a/tests/elm-verify-examples.json +++ b/tests/elm-verify-examples.json @@ -6,6 +6,7 @@ "Char.Extra", "Cmd.Extra", "Dict.Extra", + "Float.Extra", "List.Extra", "Maybe.Extra", "Order.Extra", From ce69621e332c265337b58709a967a08a3f70f0dd Mon Sep 17 00:00:00 2001 From: Jakub Hampl Date: Wed, 6 Sep 2023 12:05:12 +0300 Subject: [PATCH 2/4] Addresses some minor CR feedback --- src/Float/Extra.elm | 38 ++++++++++++++++++-------------------- tests/FloatTests.elm | 8 ++------ tests/Utils.elm | 8 ++++++++ 3 files changed, 28 insertions(+), 26 deletions(-) create mode 100644 tests/Utils.elm diff --git a/src/Float/Extra.elm b/src/Float/Extra.elm index 4d4817a..3281711 100644 --- a/src/Float/Extra.elm +++ b/src/Float/Extra.elm @@ -23,10 +23,6 @@ module Float.Extra exposing -} -import Bitwise - - - -- toFixedDecimalDigits implementation @@ -349,20 +345,22 @@ Differences from [List.range from the standard library](https://package.elm-lang -} range : Float -> Float -> Float -> List Float range start stop step = - let - n = - (stop - start) - / step - |> ceiling - -- get rid of NaN - |> Bitwise.or 0 - |> max 0 - - helper i list = - if i >= 0 then - helper (i - 1) (start + step * toFloat i :: list) + if step == 0 then + [] - else - list - in - helper (n - 1) [] + else + let + n = + (stop - start) + / step + |> ceiling + |> max 0 + + helper i list = + if i >= 0 then + helper (i - 1) (start + step * toFloat i :: list) + + else + list + in + helper (n - 1) [] diff --git a/tests/FloatTests.elm b/tests/FloatTests.elm index 3a60dc2..14b96ba 100644 --- a/tests/FloatTests.elm +++ b/tests/FloatTests.elm @@ -5,6 +5,7 @@ import Float.Extra exposing (aboutEqual) import Fuzz import List.Extra exposing (Step(..)) import Test exposing (Test, describe, fuzz, fuzz2, test) +import Utils exposing (expectAll) testToFixedDecimalPlaces : Test @@ -210,7 +211,7 @@ testRange = , Float.Extra.range 20 10 0.5 |> Expect.equal [] ] - , test "returns an empty array if start >= stop and step < 0" <| + , test "returns an empty array if start <= stop and step < 0" <| \() -> expectAll [ Float.Extra.range 5 5 -2 @@ -272,8 +273,3 @@ testRange = |> Expect.equal [ 2.0e300, 2.0e300 - 3.0e299, 2.0e300 - 3.0e299 * 2, 2.0e300 - 3.0e299 * 3 ] ] ] - - -expectAll : List Expect.Expectation -> Expect.Expectation -expectAll expectations = - Expect.all (List.map always expectations) () diff --git a/tests/Utils.elm b/tests/Utils.elm new file mode 100644 index 0000000..9d8bf42 --- /dev/null +++ b/tests/Utils.elm @@ -0,0 +1,8 @@ +module Utils exposing (expectAll) + +import Expect + + +expectAll : List Expect.Expectation -> Expect.Expectation +expectAll expectations = + Expect.all (List.map always expectations) () From e6805b56ab78c67488ed72efb2fe0170e39001a9 Mon Sep 17 00:00:00 2001 From: Jakub Hampl Date: Wed, 6 Sep 2023 13:12:19 +0300 Subject: [PATCH 3/4] Refactors toFixedSignificantDigits to be more readable --- src/Float/Extra.elm | 203 +++++++++++++++++++++++--------------------- 1 file changed, 107 insertions(+), 96 deletions(-) diff --git a/src/Float/Extra.elm b/src/Float/Extra.elm index 3281711..69d9545 100644 --- a/src/Float/Extra.elm +++ b/src/Float/Extra.elm @@ -40,113 +40,124 @@ adjustDecimalPlace x magnitude = x / 10 ^ magnitude -{-| This ugly code is a port of the Intl API +{-| As specified in -} -toRawPrecision : Float -> Int -> Int -> String -toRawPrecision x minPrecision maxPrecision = - -- IGNORE TCO - there is only so much precision to be had in JS numbers +toRawPrecision : Float -> Float -> String +toRawPrecision x precision = let - p = - toFloat maxPrecision - - defaultCase _ = - let - e_ = - toFloat <| floor <| logBase 10 <| abs x - - decimalPlaceOffset = - e_ - p + 1 - - n = - round (adjustDecimalPlace x decimalPlaceOffset) - in - if adjustDecimalPlace (toFloat n) (p - 1) >= 10 then - ( String.fromInt (n // 10), e_ + 1 ) - - else - ( String.fromInt n, e_ ) - - ( m, ex ) = - if x == 0 then - ( zeroes p, 0 ) - - else - case String.split "e" (String.fromFloat x) of - [ xToStringMantissa, xToStringExponent ] -> - case String.toFloat xToStringExponent of - Just xExponent -> - let - xToStringMantissaWithoutDecimalPoint = - String.replace "." "" xToStringMantissa - - len = - toFloat (String.length xToStringMantissaWithoutDecimalPoint) - in - if len <= p then - ( xToStringMantissaWithoutDecimalPoint ++ zeroes (p - len), xExponent ) - - else - ( xToStringMantissa - |> String.toFloat - |> Maybe.map (\v -> toRawPrecision v minPrecision maxPrecision ++ "e" ++ xToStringExponent) - |> Maybe.withDefault xToStringMantissaWithoutDecimalPoint - , --hack - p - 1 - ) - - _ -> - defaultCase () - - _ -> - defaultCase () + ( significantBaseString, decimalPointIndex ) = + toSignificantBase precision x in - if ex >= p then - m ++ zeroes (ex - p + 1) + if decimalPointIndex >= precision then + significantBaseString ++ zeroes (decimalPointIndex - precision + 1) - else if ex == p - 1 then - m + else if decimalPointIndex == precision - 1 then + significantBaseString else let - m2 = - if ex >= 0 then - String.slice 0 (floor (ex + 1)) m ++ "." ++ String.dropLeft (floor (ex + 1)) m - - else if ex < 0 then - "0." ++ zeroes -(ex + 1) ++ m + candidateString = + if decimalPointIndex >= 0 then + String.slice 0 (floor (decimalPointIndex + 1)) significantBaseString ++ "." ++ String.dropLeft (floor (decimalPointIndex + 1)) significantBaseString else - m + "0." ++ zeroes -(decimalPointIndex + 1) ++ significantBaseString in - if String.contains "." m2 && maxPrecision > minPrecision then - let - doCut toCut lst = - if toCut > 0 then - case lst of - '0' :: rst -> - doCut (toCut - 1) rst - - '.' :: rst -> - List.reverse rst - - _ -> - List.reverse lst - - else if List.head lst == Just '.' then - List.tail lst - |> Maybe.withDefault [] - |> List.reverse - - else - List.reverse lst - in - String.toList m2 - |> List.reverse - |> doCut (maxPrecision - minPrecision) - |> String.fromList + if String.contains "." candidateString && precision > minPrecision then + cutUnnecessaryDecimalZeroes (round (precision - minPrecision)) candidateString else - m2 + candidateString + + +minPrecision : Float +minPrecision = + 1 + + +toSignificantBase : Float -> Float -> ( String, Float ) +toSignificantBase precision x = + if x == 0 then + ( zeroes precision, 0 ) + + else + case String.split "e" (String.fromFloat x) of + [ xToStringMantissa, xToStringExponent ] -> + case String.toFloat xToStringExponent of + Just xExponent -> + toSignificantBaseScientific precision xToStringMantissa xToStringExponent xExponent + + _ -> + toSignificantBaseNonScientific precision x + + _ -> + toSignificantBaseNonScientific precision x + + +toSignificantBaseScientific : Float -> String -> String -> Float -> ( String, Float ) +toSignificantBaseScientific precision xToStringMantissa xToStringExponent xExponent = + let + xToStringMantissaWithoutDecimalPoint = + String.replace "." "" xToStringMantissa + + len = + toFloat (String.length xToStringMantissaWithoutDecimalPoint) + in + if len <= precision then + ( xToStringMantissaWithoutDecimalPoint ++ zeroes (precision - len), xExponent ) + + else + ( xToStringMantissa + |> String.toFloat + |> Maybe.map (\v -> toRawPrecision v precision ++ "e" ++ xToStringExponent) + |> Maybe.withDefault xToStringMantissaWithoutDecimalPoint + , precision - 1 + ) + + +toSignificantBaseNonScientific : Float -> Float -> ( String, Float ) +toSignificantBaseNonScientific precision x = + let + e_ = + toFloat <| floor <| logBase 10 <| abs x + + decimalPlaceOffset = + e_ - precision + 1 + + n = + round (adjustDecimalPlace x decimalPlaceOffset) + in + if adjustDecimalPlace (toFloat n) (precision - 1) >= 10 then + ( String.fromInt (n // 10), e_ + 1 ) + + else + ( String.fromInt n, e_ ) + + +cutUnnecessaryDecimalZeroes : Int -> String -> String +cutUnnecessaryDecimalZeroes num = + String.toList >> List.reverse >> cutUnnecessaryDecimalZeroesHelp num >> List.reverse >> String.fromList + + +cutUnnecessaryDecimalZeroesHelp : Int -> List Char -> List Char +cutUnnecessaryDecimalZeroesHelp toCut lst = + if toCut > 0 then + case lst of + '0' :: rst -> + cutUnnecessaryDecimalZeroesHelp (toCut - 1) rst + + '.' :: rst -> + rst + + _ -> + lst + + else if List.head lst == Just '.' then + List.tail lst + |> Maybe.withDefault [] + + else + lst sign : Float -> String @@ -176,7 +187,7 @@ toFixedSignificantDigits significantDigits value = sign value ++ "Infinity" else - sign value ++ toRawPrecision (abs value) 1 (max 1 significantDigits) + sign value ++ toRawPrecision (abs value) (toFloat (max 1 significantDigits)) From 07b1d0676ca9abf85548ce26475411f07c0d5353 Mon Sep 17 00:00:00 2001 From: Jakub Hampl Date: Wed, 6 Sep 2023 17:53:01 +0300 Subject: [PATCH 4/4] CR feedback --- src/Float/Extra.elm | 30 ++++++++++++++++++++---------- tests/FloatTests.elm | 25 ++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 11 deletions(-) diff --git a/src/Float/Extra.elm b/src/Float/Extra.elm index 69d9545..c4b70fc 100644 --- a/src/Float/Extra.elm +++ b/src/Float/Extra.elm @@ -135,8 +135,13 @@ toSignificantBaseNonScientific precision x = cutUnnecessaryDecimalZeroes : Int -> String -> String -cutUnnecessaryDecimalZeroes num = - String.toList >> List.reverse >> cutUnnecessaryDecimalZeroesHelp num >> List.reverse >> String.fromList +cutUnnecessaryDecimalZeroes num value = + value + |> String.toList + |> List.reverse + |> cutUnnecessaryDecimalZeroesHelp num + |> List.reverse + |> String.fromList cutUnnecessaryDecimalZeroesHelp : Int -> List Char -> List Char @@ -152,12 +157,13 @@ cutUnnecessaryDecimalZeroesHelp toCut lst = _ -> lst - else if List.head lst == Just '.' then - List.tail lst - |> Maybe.withDefault [] - else - lst + case lst of + '.' :: tail -> + tail + + _ -> + lst sign : Float -> String @@ -240,9 +246,9 @@ roundAsFloat places strNum = roundToDecimal : Int -> Float -> Float -roundToDecimal places = +roundToDecimal places value = if places < 0 then - identity + value else let @@ -258,7 +264,11 @@ roundToDecimal places = divByExp v = v / exp in - multiplyByExp >> round >> toFloat >> divByExp + value + |> multiplyByExp + |> round + |> toFloat + |> divByExp diff --git a/tests/FloatTests.elm b/tests/FloatTests.elm index 14b96ba..51a77c0 100644 --- a/tests/FloatTests.elm +++ b/tests/FloatTests.elm @@ -2,7 +2,7 @@ module FloatTests exposing (testAboutEqual, testBoundaryValuesAsUnicode, testRan import Expect import Float.Extra exposing (aboutEqual) -import Fuzz +import Fuzz exposing (Fuzzer) import List.Extra exposing (Step(..)) import Test exposing (Test, describe, fuzz, fuzz2, test) import Utils exposing (expectAll) @@ -272,4 +272,27 @@ testRange = , Float.Extra.range 2.0e300 1.0e300 -3.0e299 |> Expect.equal [ 2.0e300, 2.0e300 - 3.0e299, 2.0e300 - 3.0e299 * 2, 2.0e300 - 3.0e299 * 3 ] ] + , fuzz fuzzRangeArgs "First element is always start" <| + \( start, end, step ) -> + case Float.Extra.range start end step |> List.head of + Just v -> + Expect.within (Expect.AbsoluteOrRelative 1.0e-8 1.0e-5) start v + + Nothing -> + Expect.pass ] + + +fuzzRangeArgs : Fuzzer ( Float, Float, Float ) +fuzzRangeArgs = + -- Float.Extra.range can generate some REALLY big lists very easily + -- this fuzzer makes sure that it generates inputs that lead to + -- ranges with about 10 elements + Fuzz.map4 + (\start step count extra -> + ( start, start + (toFloat count + extra) * step, step ) + ) + Fuzz.float + Fuzz.float + (Fuzz.intRange -10 10) + (Fuzz.floatRange 0 1)