├── .gitignore ├── tests ├── elm-verify-examples.json └── Tests.elm ├── elm-tooling.json ├── elm.json ├── .github └── workflows │ └── test.yml ├── package.json ├── LICENSE ├── README.md ├── ChangeLog.md └── src └── List └── Extra.elm /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore build or dist files 2 | /elm-stuff 3 | /elm 4 | tests 5 | node_modules 6 | -------------------------------------------------------------------------------- /tests/elm-verify-examples.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": "../src", 3 | "tests": [ 4 | "List.Extra" 5 | ] 6 | } -------------------------------------------------------------------------------- /elm-tooling.json: -------------------------------------------------------------------------------- 1 | { 2 | "tools": { 3 | "elm": "0.19.1", 4 | "elm-format": "0.8.5", 5 | "elm-test-rs": "3.0.0" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "package", 3 | "name": "elm-community/list-extra", 4 | "summary": "Convenience functions for working with List", 5 | "license": "MIT", 6 | "version": "8.7.0", 7 | "exposed-modules": [ 8 | "List.Extra" 9 | ], 10 | "elm-version": "0.19.0 <= v < 0.20.0", 11 | "dependencies": { 12 | "elm/core": "1.0.0 <= v < 2.0.0" 13 | }, 14 | "test-dependencies": { 15 | "elm-explorations/test": "2.0.0 <= v < 3.0.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: "Tests" 2 | on: [push, pull_request] 3 | jobs: 4 | tests: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v2 8 | - uses: actions/setup-node@v2 9 | with: 10 | node-version: '14' 11 | cache: 'npm' 12 | - uses: actions/cache@v2 13 | with: 14 | path: ~/.elm 15 | key: ${{ runner.os }}-elm-${{ hashFiles('package-lock.json', 'elm-tooling.json', 'elm.json') }} 16 | - run: npm ci 17 | - run: npm test 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "list-extra", 3 | "version": "8.0.0", 4 | "description": "Convenience functions for working with List", 5 | "directories": { 6 | "test": "tests" 7 | }, 8 | "scripts": { 9 | "format": "elm-format --yes src tests/Tests.elm", 10 | "test:docs": "elm make --docs=docs.json && rm docs.json", 11 | "test:format": "elm-format --validate src tests/Tests.elm", 12 | "test": "elm-verify-examples && elm-test-rs && npm run test:format && npm run test:docs", 13 | "postinstall": "elm-tooling install" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/elm-community/list-extra.git" 18 | }, 19 | "author": "", 20 | "license": "ISC", 21 | "bugs": { 22 | "url": "https://github.com/elm-community/list-extra/issues" 23 | }, 24 | "homepage": "https://github.com/elm-community/list-extra#readme", 25 | "devDependencies": { 26 | "elm-doc-preview": "^5.0.5", 27 | "elm-tooling": "^1.10.0", 28 | "elm-verify-examples": "^5.2.0" 29 | } 30 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 CircuitHub Inc., Elm Community members 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Convenience functions for working with `List` 2 | 3 | Feedback and contributions are very welcome! 4 | 5 | ## Tests 6 | 7 | This package uses [elm-test](https://github.com/elm-explorations/test) and [elm-verify-examples](https://github.com/stoeffel/elm-verify-examples). 8 | 9 | ## Contributing 10 | 11 | Pull requests are welcome. You can expect some kind of response within 14 days. 12 | 13 | If you are proposing a new function be added, please adhere to the following.. 14 | 15 | 1. Include [documentation](http://package.elm-lang.org/help/documentation-format) and make sure your documentation has a code snippet demonstrating what the function does. We use [elm-verify-examples](https://github.com/stoeffel/elm-verify-examples) in our travis set up which verifies our examples that our example code is correct, so please take advantage of that. 16 | 2. Provide a detailed use case where your new function would be useful. Also, compare your new function to the best possible implementation that doesn't use your function. 17 | 3. Add tests to `Tests/Tests.elm` 18 | 19 | If you are improving existing functions please demonstrate the performance gains in something like [Ellie](https://ellie-app.com/) and by using a benchmark library like [this one](https://github.com/elm-explorations/benchmark). I usually copy and paste the last ellie bench mark I made, like [this one](https://ellie-app.com/gm9X8yfPLXMa1), so I don't have to set up the whole benchmark from scratch every time. 20 | -------------------------------------------------------------------------------- /ChangeLog.md: -------------------------------------------------------------------------------- 1 | ### 8.7.0 2 | 1. `frequencies` function, to count the number of occurences of each item in a list 3 | 2. `subsequenceNonEmpty` function, to calculate each subsequence excluding the empty list. 4 | 5 | ### 8.6.0 6 | 1. `stoppableFoldl` function and `Step` type added. A stoppable fold has better performance in cases where a fold can be terminated part way through. 7 | 8 | ### 8.5.2 9 | 1. Performance improvement to `remove` by making it tail call optimized. 10 | 2. Performance improvement to `updateAt` by only computing list head when necessary. 11 | 3. `groupsOf` and `greedyGroupsOf` are now tail call optimized, making them stack safe, but unfortunately slightly slower (small lists and groups ~20% slower). 12 | 4. Performance improvement to `isPermutationOf` by making helper functions top level, not currying functions, and putting most common `case` branches first. 13 | 14 | ### 8.5.1 15 | 1. New `isPermutationOf` implemntation in 8.5.0 did not always give the correct output. In 8.5.1 a new implementation that is both performance and correct is used. 16 | 17 | ### 8.5.0 18 | 1. `unique` and `uniqueBy` functions no longer requires comparable input arguments. This change increased performance for lists sized 0-100 elements by about 40% but decreases performance for lists sized >200 by about 35%. Seems like a worthy trade off. 19 | 2. `isPermutationOf` is vastly more performant. @lue-bird 's benchmarks show cases of being 141,000% more performant. 20 | 3. New `reverseRange`, a more performant combination of `reverse` and `range`. 21 | 22 | ### 8.4.0 23 | 1. New function `joinOn` 24 | 25 | ### 8.3.2 26 | 1. `isInfixOf` is tail call optimized 27 | 28 | ### 8.3.1 29 | 1. `gatherWith` is tail call optimized 30 | 31 | ### 8.3.0 32 | 1. New function `findMap` 33 | 34 | ### 8.2.4 35 | 1. Speed up removeAt implementation 36 | 2. Make iterate tail recursive 37 | 38 | ### 8.2.3 39 | 1. Fixed bug in `isInfixOf` that prevented the detection of infixes after a partial infix (Issue #132) 40 | 41 | ### 8.2.0 42 | Notes 43 | 1. `groupWhile` implementation rewritten to be tail-recursive to eliminate risk of stack overflow errors. Trade off is its about 12% slower. 44 | 45 | Additions 46 | 1. `pairings` 47 | 48 | ### 8.1.0 49 | Notes 50 | 1. Documentation cleaned up, and Elm verify examples implemented 51 | 52 | Additions 53 | 1. `gatherEquals`, `gatherEqualsBy`, and `gatherWith` 54 | 2. `maximumWith` and `minimumWith` 55 | 56 | ### 8.0.0 57 | Notes 58 | 1. First Elm 0.19 release 59 | 60 | Breaking Changes 61 | 1. `replaceIf` was renamed to `setIf` 62 | 2. `unzip4` and `unzip5` were removed 63 | 3. The `(!!)` operator was removed, as Elm 0.19 no longer permits custom infix operators 64 | 4. *Really Breaky*: The type signature of `foldl1` did not change, but the arguments did. `foldl1` takes a `a -> a -> a` as a parameter. However, before version 8.0.0 it had the shape `b -> a -> b` and now it is `a -> b -> b`. 65 | -------------------------------------------------------------------------------- /tests/Tests.elm: -------------------------------------------------------------------------------- 1 | module Tests exposing (all) 2 | 3 | import Expect 4 | import Fuzz exposing (int, intRange, list) 5 | import List exposing (map, range) 6 | import List.Extra exposing (..) 7 | import Test exposing (Test, describe, fuzz, fuzz2, fuzz3, test) 8 | import Tuple exposing (first) 9 | 10 | 11 | all : Test 12 | all = 13 | describe "List.Extra" 14 | [ describe "unique" <| 15 | [ test "removes duplicates" <| 16 | \() -> 17 | Expect.equal (List.Extra.unique [ 0, 1, 1, 0, 1 ]) [ 0, 1 ] 18 | , test "preserves list order" <| 19 | \() -> 20 | Expect.equal (List.Extra.unique [ 3, 3, 2, 1, 1, 0 ]) [ 3, 2, 1, 0 ] 21 | ] 22 | , describe "allDifferent" <| 23 | [ test "detects duplicates" <| 24 | \() -> 25 | Expect.equal (List.Extra.allDifferent [ 0, 1, 1, 0, 1 ]) False 26 | ] 27 | , describe "andMap" <| 28 | [ test "computes piecemeal" <| 29 | \() -> 30 | Expect.equal 31 | ([ 1, 2, 3 ] 32 | |> map (\a b c -> a + b * c) 33 | |> andMap [ 4, 5, 6 ] 34 | |> andMap [ 2, 1, 1 ] 35 | ) 36 | [ 9, 7, 9 ] 37 | ] 38 | , describe "reverseMap" <| 39 | [ test "maps and reverses" <| 40 | \() -> 41 | Expect.equal (reverseMap sqrt [ 1, 4, 9 ]) [ 3, 2, 1 ] 42 | ] 43 | , describe "reverseFilter" <| 44 | [ test "filters and reverses" <| 45 | \() -> 46 | Expect.equal (reverseFilter (\x -> x > 5) [ 1, 4, 9, 16 ]) [ 16, 9 ] 47 | ] 48 | , describe "notMember" <| 49 | [ test "disconfirms member" <| 50 | \() -> 51 | Expect.equal (notMember 1 [ 1, 2, 3 ]) False 52 | , test "confirms non-member" <| 53 | \() -> 54 | Expect.equal (notMember 4 [ 1, 2, 3 ]) True 55 | ] 56 | , describe "find" <| 57 | [ test "behaves as documented" <| 58 | \() -> 59 | Expect.equal (find (\num -> num > 5) [ 2, 4, 6, 8 ]) (Just 6) 60 | ] 61 | , describe "elemIndex" <| 62 | [ test "finds index of value" <| 63 | \() -> 64 | Expect.equal (elemIndex 1 [ 1, 2, 3 ]) (Just 0) 65 | , test "doesn't find index of non-present" <| 66 | \() -> 67 | Expect.equal (elemIndex 4 [ 1, 2, 3 ]) Nothing 68 | , test "finds index of first match" <| 69 | \() -> 70 | Expect.equal (elemIndex 1 [ 1, 2, 1 ]) (Just 0) 71 | ] 72 | , describe "elemIndices" <| 73 | [ test "finds singleton index" <| 74 | \() -> 75 | Expect.equal (elemIndices 1 [ 1, 2, 3 ]) [ 0 ] 76 | , test "doesn't find indices of non-present" <| 77 | \() -> 78 | Expect.equal (elemIndices 4 [ 1, 2, 3 ]) [] 79 | , test "finds all indices" <| 80 | \() -> 81 | Expect.equal (elemIndices 1 [ 1, 2, 1 ]) [ 0, 2 ] 82 | ] 83 | , describe "findIndex" <| 84 | [ test "finds index of value" <| 85 | \() -> 86 | Expect.equal (findIndex (\x -> modBy 2 x == 0) [ 1, 2, 3 ]) (Just 1) 87 | , test "doesn't find index of non-present" <| 88 | \() -> 89 | Expect.equal (findIndex (\x -> modBy 2 x == 0) [ 1, 3, 5 ]) Nothing 90 | , test "finds index of first match" <| 91 | \() -> 92 | Expect.equal (findIndex (\x -> modBy 2 x == 0) [ 1, 2, 4 ]) (Just 1) 93 | ] 94 | , describe "findIndices" <| 95 | [ test "finds singleton index" <| 96 | \() -> 97 | Expect.equal (findIndices (\x -> modBy 2 x == 0) [ 1, 2, 3 ]) [ 1 ] 98 | , test "doesn't find indices of non-present" <| 99 | \() -> 100 | Expect.equal (findIndices (\x -> modBy 2 x == 0) [ 1, 3, 5 ]) [] 101 | , test "finds all indices" <| 102 | \() -> 103 | Expect.equal (findIndices (\x -> modBy 2 x == 0) [ 1, 2, 4 ]) [ 1, 2 ] 104 | ] 105 | , describe "findMap" <| 106 | [ test "Nothing for empty list" <| 107 | \() -> 108 | Expect.equal (findMap identity []) Nothing 109 | , test "Finds and maps for list of one with first element matching" <| 110 | \() -> 111 | Expect.equal (findMap List.head [ [ 1 ] ]) (Just 1) 112 | , test "Fails to find and map for list of one without element matching" <| 113 | \() -> 114 | Expect.equal (findMap List.head [ [] ]) Nothing 115 | , test "Finds and maps for list with middle element matching" <| 116 | \() -> 117 | Expect.equal (findMap List.head [ [], [ 2 ], [] ]) (Just 2) 118 | , test "Finds and maps for list with last element matching" <| 119 | \() -> 120 | Expect.equal (findMap List.head [ [], [], [ 3 ] ]) (Just 3) 121 | , test "Fails to find and map for list with no element matching" <| 122 | \() -> 123 | Expect.equal (findMap List.head [ [], [], [] ]) Nothing 124 | ] 125 | , describe "count" <| 126 | [ test "isOdd predicate" <| 127 | \() -> 128 | Expect.equal (count (\n -> modBy 2 n == 1) [ 1, 2, 3, 4, 5, 6, 7 ]) 4 129 | , test "equal predicate" <| 130 | \() -> 131 | Expect.equal (count ((==) "yeah") [ "She", "loves", "you", "yeah", "yeah", "yeah" ]) 3 132 | ] 133 | , describe "intercalate" <| 134 | [ test "computes example" <| 135 | \() -> 136 | Expect.equal 137 | (intercalate [ 0, 0 ] [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ] ]) 138 | [ 1, 2, 0, 0, 3, 4, 0, 0, 5, 6 ] 139 | ] 140 | , describe "transpose" <| 141 | [ test "performs basic transpose" <| 142 | \() -> 143 | Expect.equal 144 | (transpose [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]) 145 | [ [ 1, 4 ], [ 2, 5 ], [ 3, 6 ] ] 146 | , test "truncate the matrix to the shortest row size" <| 147 | \() -> 148 | Expect.equal 149 | (transpose [ [ 10, 11 ], [ 20 ], [ 30, 31, 32 ] ]) 150 | [ [ 10, 20, 30 ] ] 151 | , test "transposes large lists" <| 152 | \() -> 153 | Expect.equal 154 | (transpose [ List.repeat 10000 1 ]) 155 | (List.repeat 10000 [ 1 ]) 156 | ] 157 | , describe "subsequences" <| 158 | [ test "computes subsequences" <| 159 | \() -> 160 | Expect.equal 161 | (subsequences [ 1, 2, 3 ]) 162 | [ [], [ 1 ], [ 2 ], [ 1, 2 ], [ 3 ], [ 1, 3 ], [ 2, 3 ], [ 1, 2, 3 ] ] 163 | ] 164 | , describe "subsequencesNonEmpty" <| 165 | [ test "computes subsequences to non-empty lists" <| 166 | \() -> 167 | Expect.equal 168 | (subsequencesNonEmpty [ 1, 2, 3 ]) 169 | [ ( 1, [] ) 170 | , ( 2, [] ) 171 | , ( 1, [ 2 ] ) 172 | , ( 3, [] ) 173 | , ( 1, [ 3 ] ) 174 | , ( 2, [ 3 ] ) 175 | , ( 1, [ 2, 3 ] ) 176 | ] 177 | ] 178 | , describe "permutations" <| 179 | [ test "computes permutations" <| 180 | \() -> 181 | Expect.equal 182 | (permutations [ 1, 2, 3 ]) 183 | [ [ 1, 2, 3 ], [ 1, 3, 2 ], [ 2, 1, 3 ], [ 2, 3, 1 ], [ 3, 1, 2 ], [ 3, 2, 1 ] ] 184 | ] 185 | , describe "isPermutationOf" 186 | [ fuzz2 (list int) (list int) "works the same as sorting" <| 187 | \a b -> 188 | isPermutationOf a b 189 | |> Expect.equal (List.sort a == List.sort b) 190 | , test "correctly notices permutations" <| 191 | \() -> 192 | Expect.all 193 | ([ [ 1, 2, 3 ], [ 1, 3, 2 ], [ 2, 1, 3 ], [ 2, 3, 1 ], [ 3, 1, 2 ], [ 3, 2, 1 ] ] 194 | |> List.map 195 | (\permutation () -> 196 | permutation 197 | |> isPermutationOf [ 1, 2, 3 ] 198 | |> Expect.equal True 199 | ) 200 | ) 201 | () 202 | , test "Notices that 1,1,1 is not a permutation of 1,2,3" <| 203 | \() -> 204 | isPermutationOf [ 1, 1, 1 ] [ 1, 2, 3 ] 205 | |> Expect.equal False 206 | , test "Notices that 1,1,2 is not a permutation of 1,2,2" <| 207 | \() -> 208 | isPermutationOf [ 1, 1, 2 ] [ 1, 2, 2 ] 209 | |> Expect.equal False 210 | , test "correctly notices non-permutations" <| 211 | \() -> 212 | Expect.all 213 | ([ [], [ 1, 3 ], [ 2, 1, 3, 2 ], [ 4, 3, 1 ] ] 214 | |> List.map 215 | (\nonPermutation () -> 216 | [ 1, 2, 3 ] 217 | |> isPermutationOf nonPermutation 218 | |> Expect.equal False 219 | ) 220 | ) 221 | () 222 | ] 223 | , describe "interweave" <| 224 | [ test "interweaves lists of equal length" <| 225 | \() -> 226 | Expect.equal (interweave [ 1, 3 ] [ 2, 4 ]) [ 1, 2, 3, 4 ] 227 | , test "appends remaining members of first list, if longer" <| 228 | \() -> 229 | Expect.equal (interweave [ 1, 3, 5, 7 ] [ 2, 4 ]) [ 1, 2, 3, 4, 5, 7 ] 230 | , test "appends remaining members of second list, if longer" <| 231 | \() -> 232 | Expect.equal (interweave [ 4, 9, 16 ] [ 2, 3, 5, 7 ]) [ 4, 2, 9, 3, 16, 5, 7 ] 233 | ] 234 | , describe "cartesianProduct" <| 235 | [ test "computes the cartesian product of lists of different length" <| 236 | \() -> 237 | Expect.equal (cartesianProduct [ [ 1, 2 ], [ 3, 4, 5 ], [ 6 ] ]) [ [ 1, 3, 6 ], [ 1, 4, 6 ], [ 1, 5, 6 ], [ 2, 3, 6 ], [ 2, 4, 6 ], [ 2, 5, 6 ] ] 238 | , test "computes the cartesian product of a single list" <| 239 | \() -> 240 | Expect.equal (cartesianProduct [ [ 1, 2 ] ]) [ [ 1 ], [ 2 ] ] 241 | , test "computes the cartesian product of lists including an empty one" <| 242 | \() -> 243 | Expect.equal (cartesianProduct [ [ 1, 2 ], [], [ 6 ] ]) [] 244 | , test "computes the nullary cartesian product" <| 245 | \() -> 246 | Expect.equal (cartesianProduct []) [ [] ] 247 | ] 248 | , describe "foldl1" <| 249 | [ test "computes minimum" <| 250 | \() -> 251 | Expect.equal (foldl1 min [ 1, 2, 3, 2, 1 ]) (Just 1) 252 | , test "computes left to right difference" <| 253 | \() -> 254 | Expect.equal (foldl1 (-) [ 1, 2, 3, 4 ]) (Just 2) 255 | , test "concats in reverse" <| 256 | \() -> 257 | Expect.equal (foldl1 (++) [ "a", "b", "c" ]) (Just "cba") 258 | , test "falls back to Nothing" <| 259 | \() -> 260 | Expect.equal (foldl1 min []) Nothing 261 | ] 262 | , describe "foldr1" <| 263 | [ test "computes minimum" <| 264 | \() -> 265 | Expect.equal (foldr1 min [ 1, 2, 3, 2, 1 ]) (Just 1) 266 | , test "computes right to left difference" <| 267 | \() -> 268 | Expect.equal (foldr1 (-) [ 1, 2, 3, 4 ]) (Just -2) 269 | , test "concats properly" <| 270 | \() -> 271 | Expect.equal (foldr1 (++) [ "a", "b", "c" ]) (Just "abc") 272 | , test "falls back to Nothing" <| 273 | \() -> 274 | Expect.equal (foldr1 min []) Nothing 275 | ] 276 | , describe "scanl1" <| 277 | [ test "computes left to right iterative sum" <| 278 | \() -> 279 | Expect.equal (scanl1 (+) [ 1, 2, 3 ]) [ 1, 3, 6 ] 280 | , test "computes left to right iterative difference" <| 281 | \() -> 282 | Expect.equal (scanl1 (-) [ 1, 2, 3 ]) [ 1, 1, 2 ] 283 | , test "computes left to right flipped iterative difference" <| 284 | \() -> 285 | Expect.equal (scanl1 (\x y -> y - x) [ 1, 2, 3 ]) [ 1, -1, -4 ] 286 | ] 287 | , describe "scanr" <| 288 | [ test "computes right to left iterative sum" <| 289 | \() -> 290 | Expect.equal (scanr (+) 0 [ 1, 2, 3 ]) [ 6, 5, 3, 0 ] 291 | , test "computes right to left iterative difference" <| 292 | \() -> 293 | Expect.equal (scanr (-) 0 [ 1, 2, 3 ]) [ 2, -1, 3, 0 ] 294 | ] 295 | , describe "scanr1" <| 296 | [ test "computes right to left iterative sum" <| 297 | \() -> 298 | Expect.equal (scanr1 (+) [ 1, 2, 3 ]) [ 6, 5, 3 ] 299 | , test "computes right to left iterative difference" <| 300 | \() -> 301 | Expect.equal (scanr1 (-) [ 1, 2, 3 ]) [ 2, -1, 3 ] 302 | , test "computes right to left flipped iterative difference" <| 303 | \() -> 304 | Expect.equal (scanr1 (\x y -> y - x) [ 1, 2, 3 ]) [ 0, 1, 3 ] 305 | ] 306 | , describe "mapAccuml" <| 307 | [ test "on empty list" <| 308 | \() -> 309 | Expect.equal 310 | (mapAccuml (\a x -> ( a + x, a * x )) 5 []) 311 | ( 5, [] ) 312 | , test "accumulate sum and map product" <| 313 | \() -> 314 | Expect.equal 315 | (mapAccuml (\a x -> ( a + x, a * x )) 5 [ 2, 4, 8 ]) 316 | ( 19, [ 10, 28, 88 ] ) 317 | , test "running total" <| 318 | \() -> 319 | Expect.equal 320 | (mapAccuml (\a x -> ( a + x, ( x, a + x ) )) 0 [ 2, 4, 8 ]) 321 | ( 14, [ ( 2, 2 ), ( 4, 6 ), ( 8, 14 ) ] ) 322 | , test "works for very long list (i.e. is call stack size safe)" <| 323 | \() -> 324 | Expect.equal 325 | (mapAccuml (\a x -> ( a + x, () )) 0 (List.range 1 100000) |> Tuple.first) 326 | 5000050000 327 | ] 328 | , describe "mapAccumr" <| 329 | [ test "on empty list" <| 330 | \() -> 331 | Expect.equal 332 | (mapAccumr (\a x -> ( a + x, a * x )) 5 []) 333 | ( 5, [] ) 334 | , test "accumulate sum and map product" <| 335 | \() -> 336 | Expect.equal 337 | (mapAccumr (\a x -> ( a + x, a * x )) 5 [ 2, 4, 8 ]) 338 | ( 19, [ 34, 52, 40 ] ) 339 | , test "add count down" <| 340 | \() -> 341 | Expect.equal 342 | (mapAccumr (\a x -> ( a + 1, ( x, a ) )) 0 [ 2, 4, 8 ]) 343 | ( 3, [ ( 2, 2 ), ( 4, 1 ), ( 8, 0 ) ] ) 344 | , test "works for very long list (i.e. is call stack size safe)" <| 345 | \() -> 346 | Expect.equal 347 | (mapAccumr (\a x -> ( a + x, () )) 0 (List.range 1 100000) |> Tuple.first) 348 | 5000050000 349 | ] 350 | , describe "unfoldr" <| 351 | [ test "builds a decreasing list from a seed" <| 352 | \() -> 353 | Expect.equal 354 | (unfoldr 355 | (\b -> 356 | if b == 0 then 357 | Nothing 358 | 359 | else 360 | Just ( b, b - 1 ) 361 | ) 362 | 5 363 | ) 364 | [ 5, 4, 3, 2, 1 ] 365 | ] 366 | , describe "iterate" <| 367 | [ test "collatz 13" <| 368 | \() -> 369 | let 370 | collatz n = 371 | if n == 1 then 372 | Nothing 373 | 374 | else 375 | Just <| 376 | if modBy 2 n == 0 then 377 | n // 2 378 | 379 | else 380 | 3 * n + 1 381 | in 382 | Expect.equal (iterate collatz 13) [ 13, 40, 20, 10, 5, 16, 8, 4, 2, 1 ] 383 | , test "should not raise RangeError" <| 384 | \() -> 385 | let 386 | loop n = 387 | if n == 100000 then 388 | Nothing 389 | 390 | else 391 | Just (n + 1) 392 | 393 | _ = 394 | iterate loop 1 395 | in 396 | Expect.pass 397 | ] 398 | , describe "init" <| 399 | [ test "handles an empty list" <| 400 | \() -> 401 | Expect.equal (init []) Nothing 402 | , fuzz int "handles a nearly-empty list" <| 403 | \x -> 404 | Expect.equal (init [ x ]) (Just []) 405 | , fuzz2 (list int) int "handles a non-empty list" <| 406 | \list x -> 407 | Expect.equal (init <| list ++ [ x ]) (Just list) 408 | ] 409 | , describe "initialize" <| 410 | [ test "creates a list starting from zero" <| 411 | \() -> 412 | Expect.equal (initialize 5 identity) [ 0, 1, 2, 3, 4 ] 413 | , test "creates a list by doubling the index" <| 414 | \() -> 415 | Expect.equal (initialize 5 (\x -> x * 2)) [ 0, 2, 4, 6, 8 ] 416 | , test "creates a list of identical values" <| 417 | \() -> 418 | Expect.equal (initialize 1 (always 3)) [ 3 ] 419 | ] 420 | , describe "cycle" <| 421 | [ test "same length" <| 422 | \() -> 423 | Expect.equal (cycle 3 [ 4, 7, 8 ]) [ 4, 7, 8 ] 424 | , test "multiple of length" <| 425 | \() -> 426 | Expect.equal (cycle 6 [ 4, 7, 8 ]) [ 4, 7, 8, 4, 7, 8 ] 427 | , test "partial cycle" <| 428 | \() -> 429 | Expect.equal (cycle 4 [ 'a', 'b', 'c' ]) [ 'a', 'b', 'c', 'a' ] 430 | , test "empty list" <| 431 | \() -> 432 | Expect.equal (cycle 9001 []) [] 433 | , test "resulting length smaller than cycle length" <| 434 | \() -> 435 | Expect.equal (cycle 2 [ 1, 2, 3, 4, 5 ]) [ 1, 2 ] 436 | ] 437 | , describe "reverseRange" 438 | [ let 439 | rangeCeiling = 440 | 10000 441 | 442 | rangeFloor = 443 | negate rangeCeiling 444 | in 445 | fuzz2 (intRange rangeFloor rangeCeiling) (intRange rangeFloor rangeCeiling) "always equal to the reverse of List.range" <| 446 | \hi lo -> 447 | reverseRange hi lo 448 | |> Expect.equalLists (List.reverse (List.range lo hi)) 449 | ] 450 | , describe "splitAt" <| 451 | [ test "splits a list in the middle" <| 452 | \() -> 453 | Expect.equal (splitAt 3 [ 1, 2, 3, 4, 5 ]) ( [ 1, 2, 3 ], [ 4, 5 ] ) 454 | , test "splits a list at the first element" <| 455 | \() -> 456 | Expect.equal (splitAt 1 [ 1, 2, 3 ]) ( [ 1 ], [ 2, 3 ] ) 457 | , test "splits the entire list correctly" <| 458 | \() -> 459 | Expect.equal (splitAt 3 [ 1, 2, 3 ]) ( [ 1, 2, 3 ], [] ) 460 | , test "splits past the length of the list" <| 461 | \() -> 462 | Expect.equal (splitAt 4 [ 1, 2, 3 ]) ( [ 1, 2, 3 ], [] ) 463 | , test "handles zero correctly" <| 464 | \() -> 465 | Expect.equal (splitAt 0 [ 1, 2, 3 ]) ( [], [ 1, 2, 3 ] ) 466 | , test "handles negative numbers correctly" <| 467 | \() -> 468 | Expect.equal (splitAt -1 [ 1, 2, 3 ]) ( [], [ 1, 2, 3 ] ) 469 | ] 470 | , describe "splitWhen" <| 471 | [ test "returns split list when predicate is true" <| 472 | \() -> 473 | Expect.equal (splitWhen (\n -> n == 3) [ 1, 2, 3, 4, 5 ]) (Just ( [ 1, 2 ], [ 3, 4, 5 ] )) 474 | , test "returns nothing when predicate is false" <| 475 | \() -> 476 | Expect.equal (splitWhen (\n -> n == 6) [ 1, 2, 3, 4, 5 ]) Nothing 477 | ] 478 | , describe "takeWhileRight" <| 479 | [ test "keeps the correct items" <| 480 | \() -> 481 | Expect.equal (takeWhileRight ((<) 5) (range 1 10)) [ 6, 7, 8, 9, 10 ] 482 | , test "drops the correct items" <| 483 | \() -> 484 | Expect.equal (dropWhileRight ((<) 5) (range 1 10)) [ 1, 2, 3, 4, 5 ] 485 | ] 486 | , describe "takeWhile" <| 487 | [ test "doesn't exceed maximum call stack" <| 488 | \() -> 489 | Expect.equal (takeWhile ((>) 19999) (range 1 20000)) (range 1 19998) 490 | ] 491 | , describe "span" <| 492 | [ test "splits in the middle of the list" <| 493 | \() -> 494 | Expect.equal (span ((>) 3) [ 1, 2, 3, 4, 1, 2, 3, 4 ]) ( [ 1, 2 ], [ 3, 4, 1, 2, 3, 4 ] ) 495 | , test "every element passes predicate" <| 496 | \() -> 497 | Expect.equal (span ((>) 5) [ 1, 2, 3 ]) ( [ 1, 2, 3 ], [] ) 498 | , test "first item doesn't pass predicate" <| 499 | \() -> 500 | Expect.equal (span ((>) 0) [ 1, 2, 3 ]) ( [], [ 1, 2, 3 ] ) 501 | ] 502 | , describe "break" <| 503 | [ test "breaks in the middle of the list" <| 504 | \() -> 505 | Expect.equal (break ((<) 3) [ 1, 2, 3, 4, 1, 2, 3, 4 ]) ( [ 1, 2, 3 ], [ 4, 1, 2, 3, 4 ] ) 506 | , test "breaks on the first item" <| 507 | \() -> 508 | Expect.equal (break ((>) 5) [ 1, 2, 3 ]) ( [], [ 1, 2, 3 ] ) 509 | , test "doesn't break for any element" <| 510 | \() -> 511 | Expect.equal (break ((<) 5) [ 1, 2, 3 ]) ( [ 1, 2, 3 ], [] ) 512 | ] 513 | , describe "stripPrefix" <| 514 | [ test "removes a matching prefix" <| 515 | \() -> 516 | Expect.equal (stripPrefix [ 1, 2 ] [ 1, 2, 3, 4 ]) (Just [ 3, 4 ]) 517 | , test "removes a matching 3-element prefix" <| 518 | \() -> 519 | Expect.equal (stripPrefix [ 1, 2, 3 ] [ 1, 2, 3, 4, 5 ]) (Just [ 4, 5 ]) 520 | , test "can remove the entire list" <| 521 | \() -> 522 | Expect.equal (stripPrefix [ 1, 2, 3 ] [ 1, 2, 3 ]) (Just []) 523 | , test "fails when prefix is longer than list" <| 524 | \() -> 525 | Expect.equal (stripPrefix [ 1, 2, 3 ] [ 1, 2 ]) Nothing 526 | , test "fails when list doesn't contain prefix" <| 527 | \() -> 528 | Expect.equal (stripPrefix [ 3, 2, 1 ] [ 1, 2, 3, 4, 5 ]) Nothing 529 | ] 530 | , describe "group" <| 531 | [ test "groups elements correctly" <| 532 | \() -> 533 | Expect.equal (group [ 1, 2, 2, 3, 3, 3, 2, 2, 1 ]) 534 | [ ( 1, [] ), ( 2, [ 2 ] ), ( 3, [ 3, 3 ] ), ( 2, [ 2 ] ), ( 1, [] ) ] 535 | ] 536 | , describe "groupWhile" <| 537 | [ test "groups by sub-element equality" <| 538 | \() -> 539 | Expect.equal 540 | (groupWhile (\x y -> first x == first y) [ ( 0, 'a' ), ( 0, 'b' ), ( 1, 'c' ), ( 1, 'd' ) ]) 541 | [ ( ( 0, 'a' ), [ ( 0, 'b' ) ] ), ( ( 1, 'c' ), [ ( 1, 'd' ) ] ) ] 542 | , test "comparison function is reflexive, symmetric, and transitive" <| 543 | \() -> 544 | Expect.equal 545 | (groupWhile (<) [ 1, 2, 3, 2, 4, 1, 3, 2, 1 ]) 546 | [ ( 1, [ 2, 3 ] ), ( 2, [ 4 ] ), ( 1, [ 3 ] ), ( 2, [] ), ( 1, [] ) ] 547 | ] 548 | , describe "inits" <| 549 | [ test "returns all initial segments" <| 550 | \() -> 551 | Expect.equal (inits [ 1, 2, 3 ]) [ [], [ 1 ], [ 1, 2 ], [ 1, 2, 3 ] ] 552 | ] 553 | , describe "tails" <| 554 | [ test "returns all final segments" <| 555 | \() -> 556 | Expect.equal (tails [ 1, 2, 3 ]) [ [ 1, 2, 3 ], [ 2, 3 ], [ 3 ], [] ] 557 | ] 558 | , describe "select" <| 559 | [ test "returns all variations with a single item removed" <| 560 | \() -> 561 | Expect.equal 562 | (select [ 1, 2, 3, 4 ]) 563 | [ ( 1, [ 2, 3, 4 ] ), ( 2, [ 1, 3, 4 ] ), ( 3, [ 1, 2, 4 ] ), ( 4, [ 1, 2, 3 ] ) ] 564 | ] 565 | , describe "selectSplit" <| 566 | [ test "returns all splits at a single item" <| 567 | \() -> 568 | Expect.equal (selectSplit [ 1, 2, 3 ]) [ ( [], 1, [ 2, 3 ] ), ( [ 1 ], 2, [ 3 ] ), ( [ 1, 2 ], 3, [] ) ] 569 | ] 570 | , describe "isSubsequenceOf" <| 571 | [ test "success" <| 572 | \() -> 573 | isSubsequenceOf [ "E", "l", "m" ] [ "E", "a", "t", " ", "l", "i", "m", "e", "s" ] 574 | |> Expect.equal True 575 | |> Expect.onFail "Elm is a subsequence of Eat lime" 576 | , test "failure" <| 577 | \() -> 578 | isSubsequenceOf [ "E", "l", "m" ] [ "E", "m", "a", "i", "l" ] 579 | |> Expect.equal False 580 | |> Expect.onFail "Elm is not a subsequence of Email" 581 | , test "success at last element" <| 582 | \() -> 583 | isSubsequenceOf [ 1, 3 ] [ 1, 2, 3 ] 584 | |> Expect.equal True 585 | |> Expect.onFail "[] should be a subsequence of []" 586 | ] 587 | , describe "lift2" <| 588 | [ test "produces all combinations of addition" <| 589 | \() -> 590 | Expect.equal (lift2 (+) [ 1, 2, 3 ] [ 4, 5 ]) [ 5, 6, 6, 7, 7, 8 ] 591 | ] 592 | , describe "groupsOf" <| 593 | [ test "groups by the correct number of items" <| 594 | \() -> 595 | Expect.equal (groupsOf 3 (range 1 10)) 596 | [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ] 597 | ] 598 | , describe "groupsOfWithStep" <| 599 | [ test "step == size" <| 600 | \() -> 601 | Expect.equal (groupsOfWithStep 4 4 (range 1 10)) 602 | [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ] ] 603 | , test "step < size" <| 604 | \() -> 605 | Expect.equal (groupsOfWithStep 3 1 (range 1 5)) 606 | [ [ 1, 2, 3 ], [ 2, 3, 4 ], [ 3, 4, 5 ] ] 607 | , test "step > size" <| 608 | \() -> 609 | Expect.equal (groupsOfWithStep 3 6 (range 1 20)) 610 | [ [ 1, 2, 3 ], [ 7, 8, 9 ], [ 13, 14, 15 ] ] 611 | ] 612 | , describe "groupsOfVarying" <| 613 | [ test "group sizes match passed sizes" <| 614 | \() -> 615 | Expect.equal 616 | (groupsOfVarying [ 2, 3, 1 ] [ "a", "b", "c", "d", "e", "f" ]) 617 | [ [ "a", "b" ], [ "c", "d", "e" ], [ "f" ] ] 618 | , test "groups correctly when passed counts are less than list size" <| 619 | \() -> 620 | Expect.equal 621 | (groupsOfVarying [ 2 ] [ "a", "b", "c", "d", "e", "f" ]) 622 | [ [ "a", "b" ] ] 623 | , test "groups correctly when passed counts are greater than list size" <| 624 | \() -> 625 | Expect.equal 626 | (groupsOfVarying [ 2, 3, 1, 5, 6 ] [ "a", "b", "c", "d", "e" ]) 627 | [ [ "a", "b" ], [ "c", "d", "e" ] ] 628 | ] 629 | , describe "greedyGroupsOf" <| 630 | [ test "groups correctly while keeping trailing group" <| 631 | \() -> 632 | Expect.equal (greedyGroupsOf 3 (range 1 10)) 633 | [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ], [ 10 ] ] 634 | ] 635 | , describe "greedyGroupsOfWithStep" <| 636 | [ test "step == size" <| 637 | \() -> 638 | Expect.equal (greedyGroupsOfWithStep 4 4 (range 1 10)) 639 | [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9, 10 ] ] 640 | , test "step < size" <| 641 | \() -> 642 | Expect.equal (greedyGroupsOfWithStep 3 2 (range 1 6)) 643 | [ [ 1, 2, 3 ], [ 3, 4, 5 ], [ 5, 6 ] ] 644 | , test "step > size" <| 645 | \() -> 646 | Expect.equal (greedyGroupsOfWithStep 3 6 (range 1 20)) 647 | [ [ 1, 2, 3 ], [ 7, 8, 9 ], [ 13, 14, 15 ], [ 19, 20 ] ] 648 | ] 649 | , describe "isPrefixOf" 650 | [ fuzz (list int) "[] is prefix to anything" <| 651 | \list -> 652 | List.Extra.isPrefixOf [] list 653 | |> Expect.equal True 654 | |> Expect.onFail "Expected [] to be a prefix." 655 | , fuzz (list int) "reflexivity" <| 656 | \list -> 657 | List.Extra.isPrefixOf list list 658 | |> Expect.equal True 659 | |> Expect.onFail "Expected list to be a prefix of itself." 660 | , fuzz2 (list int) (list int) "antisymmetry" <| 661 | \listA listB -> 662 | not (List.Extra.isPrefixOf listA listB) 663 | || not (List.Extra.isPrefixOf listB listA) 664 | || listA 665 | == listB 666 | |> Expect.equal True 667 | |> Expect.onFail "Expected exactly one to be prefix of the other." 668 | , fuzz3 (list int) (list int) (list int) "transitivity" <| 669 | \listA listB listC -> 670 | not (List.Extra.isPrefixOf listA listB) 671 | || not (List.Extra.isPrefixOf listB listC) 672 | || List.Extra.isPrefixOf listA listC 673 | |> Expect.equal True 674 | |> Expect.onFail "Expected prefix of prefix to be prefix." 675 | , test "stack safety" <| 676 | \() -> 677 | isPrefixOf (List.range 1 6000) (List.range 1 10000) 678 | |> Expect.equal True 679 | |> Expect.onFail "1, 2, ..., 6k is prefix of 1, 2, ..., 10k" 680 | , fuzz2 (list int) (list int) "generalized fuzz test" <| 681 | \prefix rest -> 682 | isPrefixOf prefix (prefix ++ rest) 683 | |> Expect.equal True 684 | |> Expect.onFail "xs is prefix of xs ++ ys" 685 | ] 686 | , describe "isSuffixOf" 687 | [ fuzz (list int) "[] is suffix to anything" <| 688 | \list -> 689 | List.Extra.isSuffixOf [] list 690 | |> Expect.equal True 691 | |> Expect.onFail "Expected [] to be a suffix." 692 | , fuzz (list int) "reflexivity" <| 693 | \list -> 694 | List.Extra.isSuffixOf list list 695 | |> Expect.equal True 696 | |> Expect.onFail "Expected list to be a suffix of itself." 697 | , fuzz2 (list int) (list int) "antisymmetry" <| 698 | \listA listB -> 699 | not (List.Extra.isSuffixOf listA listB) 700 | || not (List.Extra.isSuffixOf listB listA) 701 | || listA 702 | == listB 703 | |> Expect.equal True 704 | |> Expect.onFail "Expected exactly one to be suffix of the other." 705 | , fuzz3 (list int) (list int) (list int) "transitivity" <| 706 | \listA listB listC -> 707 | not (List.Extra.isSuffixOf listA listB) 708 | || not (List.Extra.isSuffixOf listB listC) 709 | || List.Extra.isSuffixOf listA listC 710 | |> Expect.equal True 711 | |> Expect.onFail "Expected suffix of suffix to be suffix." 712 | , test "stack safety" <| 713 | \() -> 714 | isSuffixOf (List.range 4000 10000) (List.range 1 10000) 715 | |> Expect.equal True 716 | |> Expect.onFail "4000, 4001, ..., 10k is suffix of 1, 2, ..., 10k" 717 | , fuzz2 (list int) (list int) "generalized fuzz test" <| 718 | \suffix rest -> 719 | isSuffixOf suffix (rest ++ suffix) 720 | |> Expect.equal True 721 | |> Expect.onFail "ys is suffix of xs ++ ys" 722 | ] 723 | , describe "isInfixOf" 724 | [ test "success" <| 725 | \() -> 726 | isInfixOf [ 5, 7, 11 ] [ 2, 3, 5, 7, 11, 13 ] 727 | |> Expect.equal True 728 | |> Expect.onFail "5, 7, 11 is infix of 2, 3, 5, 7, 11, 13" 729 | , test "not consecutive" <| 730 | \() -> 731 | isInfixOf [ 5, 7, 13 ] [ 2, 3, 5, 7, 11, 13 ] 732 | |> Expect.equal False 733 | |> Expect.onFail "5, 7, 13 is not infix of 2, 3, 5, 7, 11, 13" 734 | , test "not in-order" <| 735 | \() -> 736 | isInfixOf [ 3, 5, 2 ] [ 2, 3, 5, 7, 11, 13 ] 737 | |> Expect.equal False 738 | |> Expect.onFail "3, 5, 2 is not infix of 2, 3, 5, 7, 11, 13" 739 | , test "partial match then real match" <| 740 | \() -> 741 | isInfixOf [ 1, 2 ] [ 1, 3, 1, 2 ] 742 | |> Expect.equal True 743 | |> Expect.onFail "1, 2 is infix of 1, 3, 1, 2" 744 | , test "stack safety" <| 745 | \() -> 746 | isInfixOf (List.range 1 6000) (List.range 1 10000) 747 | |> Expect.equal True 748 | |> Expect.onFail "1, 2, ..., 6k is infix of 1, 2, ..., 10k" 749 | , fuzz3 (list int) (list int) (list int) "generalized fuzz test" <| 750 | \prefix match suffix -> 751 | isInfixOf match (prefix ++ match ++ suffix) 752 | |> Expect.equal True 753 | |> Expect.onFail "ys is infix of xs ++ ys ++ zs" 754 | , test "empty is infix of empty" <| 755 | \() -> 756 | isInfixOf [] [] 757 | |> Expect.equal True 758 | |> Expect.onFail "empty is infix of empty" 759 | , fuzz (list int) "empty is infix of anything" <| 760 | \list -> 761 | isInfixOf [] list 762 | |> Expect.equal True 763 | |> Expect.onFail "empty is infix of anything" 764 | , fuzz2 int (list int) "non-empty is not infix of empty" <| 765 | \x xs -> 766 | isInfixOf (x :: xs) [] 767 | |> Expect.equal False 768 | |> Expect.onFail "non-empty is not infix of empty" 769 | , fuzz (list int) "equal lists are infix" <| 770 | \list -> 771 | isInfixOf list list 772 | |> Expect.equal True 773 | |> Expect.onFail "equal lists are infix" 774 | , test "is stack safe" <| 775 | \() -> 776 | isInfixOf [ 5, 7, 13 ] (List.repeat 1000000 5) 777 | |> Expect.equal False 778 | |> Expect.onFail "5, 7, 13 is not infix of 2, 3, 5, 7, 11, 13" 779 | ] 780 | , describe "swapAt" 781 | [ test "negative index as first argument returns the original list" <| 782 | \() -> 783 | Expect.equal (swapAt -1 0 [ 1, 2, 3 ]) [ 1, 2, 3 ] 784 | , test "negative index as second argument returns the original list" <| 785 | \() -> 786 | Expect.equal (swapAt 0 -1 [ 1, 2, 3 ]) [ 1, 2, 3 ] 787 | , test "out of range index as first argument returns the original list" <| 788 | \() -> 789 | Expect.equal (swapAt 10 0 [ 1, 2, 3 ]) [ 1, 2, 3 ] 790 | , test "out of range index as second argument returns the original list" <| 791 | \() -> 792 | Expect.equal (swapAt 0 -1 [ 1, 2, 3 ]) [ 1, 2, 3 ] 793 | , test "identical indexes returns the original list" <| 794 | \() -> 795 | Expect.equal (swapAt 1 1 [ 1, 2, 3 ]) [ 1, 2, 3 ] 796 | , test "swap the elements at indices 0 and 1" <| 797 | \() -> 798 | Expect.equal (swapAt 0 1 [ 1, 2, 3 ]) [ 2, 1, 3 ] 799 | ] 800 | , describe "removeAt" 801 | [ test "negative index returns the original list" <| 802 | \() -> 803 | Expect.equal (removeAt -1 [ 1, 2, 3 ]) [ 1, 2, 3 ] 804 | , test "remove the element at index 0" <| 805 | \() -> 806 | Expect.equal (removeAt 0 [ 1, 2, 3 ]) [ 2, 3 ] 807 | , test "remove the element at index 2" <| 808 | \() -> 809 | Expect.equal (removeAt 2 [ 1, 2, 3 ]) [ 1, 2 ] 810 | , test "out of range index returns the original list" <| 811 | \() -> 812 | Expect.equal (removeAt 4 [ 1, 2, 3 ]) [ 1, 2, 3 ] 813 | ] 814 | , describe "setAt" 815 | [ test "negative index returns the original list" <| 816 | \() -> 817 | Expect.equal (setAt -1 9 [ 1, 2, 3 ]) [ 1, 2, 3 ] 818 | , test "set index 0 to 9" <| 819 | \() -> 820 | Expect.equal (setAt 0 9 [ 1, 2, 3 ]) [ 9, 2, 3 ] 821 | , test "set index 2 to 9" <| 822 | \() -> 823 | Expect.equal (setAt 2 9 [ 1, 2, 3 ]) [ 1, 2, 9 ] 824 | , test "out of range index returns the original list" <| 825 | \() -> 826 | Expect.equal (setAt 4 9 [ 1, 2, 3 ]) [ 1, 2, 3 ] 827 | ] 828 | , describe "updateAt" 829 | [ test "negative index returns the original list" <| 830 | \() -> 831 | Expect.equal (updateAt -1 ((+) 1) [ 1, 2, 3 ]) [ 1, 2, 3 ] 832 | , test "increment the element at index 0" <| 833 | \() -> 834 | Expect.equal (updateAt 0 ((+) 1) [ 1, 2, 3 ]) [ 2, 2, 3 ] 835 | , test "increment the element at index 2" <| 836 | \() -> 837 | Expect.equal (updateAt 2 ((+) 1) [ 1, 2, 3 ]) [ 1, 2, 4 ] 838 | , test "out of range index returns the original list" <| 839 | \() -> 840 | Expect.equal (updateAt 4 ((+) 1) [ 1, 2, 3 ]) [ 1, 2, 3 ] 841 | ] 842 | , describe "updateIfIndex" 843 | [ test "increments first element" <| 844 | \() -> 845 | Expect.equal (updateIfIndex (always True) ((+) 1) [ 1, 2, 3 ]) [ 2, 3, 4 ] 846 | , test "if the index is 2, then increment the element" <| 847 | \() -> 848 | Expect.equal (updateIfIndex ((==) 2) ((+) 1) [ 1, 2, 3 ]) [ 1, 2, 4 ] 849 | , test "if the index is even, increment the element" <| 850 | \() -> 851 | Expect.equal (updateIfIndex (\index -> modBy 2 index == 0) ((+) 1) [ 1, 2, 3 ]) [ 2, 2, 4 ] 852 | ] 853 | , describe "remove" 854 | [ test "leaves the list untouched if the value is not in the list" <| 855 | \() -> 856 | let 857 | list : List Int 858 | list = 859 | [ 1, 2, 3 ] 860 | in 861 | list 862 | |> remove 1000 863 | |> Expect.equal list 864 | , test "removes the element if it's present in the list" <| 865 | \() -> 866 | [ 1, 2, 3 ] 867 | |> remove 2 868 | |> Expect.equal [ 1, 3 ] 869 | , test "removes only the first element" <| 870 | \() -> 871 | [ 1, 2, 3, 3, 3 ] 872 | |> remove 3 873 | |> Expect.equal [ 1, 2, 3, 3 ] 874 | , test "is stack-safe" <| 875 | \() -> 876 | let 877 | list : List Int 878 | list = 879 | List.range 1 10000 880 | in 881 | list 882 | |> remove 100000 883 | |> Expect.equal list 884 | ] 885 | , describe "removeIfIndex" 886 | [ test "remove all the elements" <| 887 | \() -> 888 | Expect.equal (removeIfIndex (always True) [ 1, 2, 3 ]) [] 889 | , test "remove the element at index 2" <| 890 | \() -> 891 | Expect.equal (removeIfIndex ((==) 2) [ 1, 2, 3 ]) [ 1, 2 ] 892 | , test "remove all elements at even indices" <| 893 | \() -> 894 | Expect.equal (removeIfIndex (\index -> modBy 2 index == 0) [ 1, 2, 3 ]) [ 2 ] 895 | ] 896 | , describe "unconsLast" 897 | [ test "removes last element of list" <| 898 | \() -> 899 | Expect.equal (unconsLast [ 1, 2, 3 ]) (Just ( 3, [ 1, 2 ] )) 900 | , test "returns Nothing if the list is empty" <| 901 | \() -> 902 | Expect.equal (unconsLast []) Nothing 903 | ] 904 | , describe "maximumWith" 905 | [ test "maximum of empty list" <| 906 | \() -> 907 | Expect.equal (maximumWith compare []) Nothing 908 | , test "first maximum of records list" <| 909 | \() -> 910 | Expect.equal 911 | (maximumWith (\x y -> compare x.val y.val) [ { id = 1, val = 1 }, { id = 2, val = 2 }, { id = 3, val = 2 } ]) 912 | (Just { id = 2, val = 2 }) 913 | ] 914 | , describe "maximumBy" 915 | [ test "maximumBy of empty list" <| 916 | \() -> Expect.equal (maximumBy (\x -> x) []) Nothing 917 | , test "first maximumBy of records list" <| 918 | \() -> 919 | Expect.equal (maximumBy (\x -> x.val) [ { id = 1, val = 1 }, { id = 2, val = 2 }, { id = 3, val = 2 } ]) 920 | (Just { id = 2, val = 2 }) 921 | ] 922 | , describe "minimumWith" 923 | [ test "minimum of empty list" <| 924 | \() -> 925 | Expect.equal (minimumWith compare []) Nothing 926 | , test "first minimum of records list" <| 927 | \() -> 928 | Expect.equal 929 | (minimumWith (\x y -> compare x.val y.val) [ { id = 1, val = 2 }, { id = 2, val = 1 }, { id = 3, val = 1 } ]) 930 | (Just { id = 2, val = 1 }) 931 | ] 932 | , describe "minimumBy" 933 | [ test "minimumBy of empty list" <| 934 | \() -> Expect.equal (minimumBy (\x -> x) []) Nothing 935 | , test "first minimumBy of records list" <| 936 | \() -> 937 | Expect.equal (minimumBy (\x -> x.val) [ { id = 1, val = 2 }, { id = 2, val = 1 }, { id = 3, val = 1 } ]) 938 | (Just { id = 2, val = 1 }) 939 | ] 940 | , describe "setIf" 941 | [ test "empty list" <| 942 | \() -> 943 | Expect.equal (setIf ((==) 1) 0 []) [] 944 | , test "set all" <| 945 | \() -> 946 | Expect.equal (setIf (always True) 2 [ 1, 2, 3, 4 ]) [ 2, 2, 2, 2 ] 947 | , test "set only evens" <| 948 | \() -> 949 | Expect.equal (setIf (\x -> modBy 2 x == 0) 0 [ 17, 8, 2, 9 ]) [ 17, 0, 0, 9 ] 950 | ] 951 | , describe "gatherEquals" 952 | [ test "empty list" <| 953 | \() -> 954 | gatherEquals [] 955 | |> Expect.equal [] 956 | , test "single element" <| 957 | \() -> 958 | gatherEquals [ 1 ] 959 | |> Expect.equal [ ( 1, [] ) ] 960 | , test "proper test" <| 961 | \() -> 962 | gatherEquals [ 1, 2, 1, 2, 3, 4, 1 ] 963 | |> Expect.equal 964 | [ ( 1, [ 1, 1 ] ) 965 | , ( 2, [ 2 ] ) 966 | , ( 3, [] ) 967 | , ( 4, [] ) 968 | ] 969 | ] 970 | , describe "gatherEqualsBy" 971 | [ test "empty list" <| 972 | \() -> 973 | gatherEqualsBy identity [] 974 | |> Expect.equal [] 975 | , test "single element" <| 976 | \() -> 977 | gatherEqualsBy identity [ 1 ] 978 | |> Expect.equal [ ( 1, [] ) ] 979 | , test "proper test" <| 980 | \() -> 981 | gatherEqualsBy identity [ 1, 2, 1, 2, 3, 4, 1 ] 982 | |> Expect.equal 983 | [ ( 1, [ 1, 1 ] ) 984 | , ( 2, [ 2 ] ) 985 | , ( 3, [] ) 986 | , ( 4, [] ) 987 | ] 988 | ] 989 | , describe "gatherWith" 990 | [ test "empty list" <| 991 | \() -> 992 | gatherWith (==) [] 993 | |> Expect.equal [] 994 | , test "single element" <| 995 | \() -> 996 | gatherWith (==) [ 1 ] 997 | |> Expect.equal [ ( 1, [] ) ] 998 | , test "proper test" <| 999 | \() -> 1000 | gatherWith (==) [ 1, 2, 1, 2, 3, 4, 1 ] 1001 | |> Expect.equal 1002 | [ ( 1, [ 1, 1 ] ) 1003 | , ( 2, [ 2 ] ) 1004 | , ( 3, [] ) 1005 | , ( 4, [] ) 1006 | ] 1007 | ] 1008 | , describe "uniquePairs" 1009 | [ test "empty list" <| 1010 | \() -> 1011 | uniquePairs [] 1012 | |> Expect.equal [] 1013 | , test "single element has no counterpart to pair with" <| 1014 | \() -> 1015 | uniquePairs [ 1 ] 1016 | |> Expect.equal [] 1017 | , test "two elements have exactly one way to pair" <| 1018 | \() -> 1019 | uniquePairs [ 1, 2 ] 1020 | |> Expect.equal [ ( 1, 2 ) ] 1021 | , test "three elements have three ways to pair" <| 1022 | \() -> 1023 | uniquePairs [ 1, 2, 3 ] 1024 | |> Expect.equal [ ( 1, 2 ), ( 1, 3 ), ( 2, 3 ) ] 1025 | ] 1026 | , describe "joinOn" 1027 | [ test "with first list empty" <| 1028 | \() -> 1029 | joinOn Tuple.pair identity identity [] [ 1, 2, 3 ] 1030 | |> Expect.equal [] 1031 | , test "with second list empty" <| 1032 | \() -> 1033 | joinOn Tuple.pair identity identity [ 1, 2, 3 ] [] 1034 | |> Expect.equal [] 1035 | , test "with neither list empty" <| 1036 | \() -> 1037 | joinOn Tuple.pair identity identity [ 1, 3, 2 ] [ 2, 1, 3 ] 1038 | |> Expect.equal [ ( 3, 3 ), ( 2, 2 ), ( 1, 1 ) ] 1039 | ] 1040 | , describe "frequencies" 1041 | [ describe "Property testing with fuzz" 1042 | [ fuzz (list int) "Final value similar list and List.sort list" <| 1043 | \list -> 1044 | frequencies list 1045 | |> List.sort 1046 | |> Expect.equal (frequencies list) 1047 | , fuzz (list int) "Final value similar, no matter the order of composition for frequencies and List.sort" <| 1048 | \list -> 1049 | let 1050 | freqFirst = 1051 | list 1052 | |> frequencies 1053 | |> List.sort 1054 | 1055 | sortFirst = 1056 | list 1057 | |> List.sort 1058 | |> frequencies 1059 | in 1060 | freqFirst 1061 | |> Expect.equal sortFirst 1062 | , fuzz2 (list int) (list int) "Two (different/similar) lists should give 2 (different/similar) results" <| 1063 | \list1 list2 -> 1064 | let 1065 | areListsSimilar = 1066 | isPermutationOf list2 list1 1067 | 1068 | freq1 = 1069 | frequencies list1 1070 | 1071 | freq2 = 1072 | frequencies list2 1073 | 1074 | shouldFreqsBeSimilar = 1075 | areListsSimilar 1076 | 1077 | areFreqsSimilar = 1078 | isPermutationOf freq2 freq1 1079 | in 1080 | areFreqsSimilar 1081 | |> Expect.equal shouldFreqsBeSimilar 1082 | ] 1083 | , describe "Unit testing on basic examples" 1084 | [ test "Frequencies on List Int" <| 1085 | \() -> 1086 | frequencies [ 4, 1, 3, 2, 2, 4, 3, 3, 4, 4 ] 1087 | |> Expect.equal [ ( 1, 1 ), ( 2, 2 ), ( 3, 3 ), ( 4, 4 ) ] 1088 | , test "Frequencies on List String" <| 1089 | \() -> 1090 | frequencies [ "a", "b", "aa", "c", "b", "aa", "c", "C", "C", "D" ] 1091 | |> Expect.equal [ ( "C", 2 ), ( "D", 1 ), ( "a", 1 ), ( "aa", 2 ), ( "b", 2 ), ( "c", 2 ) ] 1092 | , test "Frequencies on empty List a" <| 1093 | \() -> 1094 | frequencies [] 1095 | |> Expect.equal [] 1096 | ] 1097 | ] 1098 | , describe "stoppableFoldl" 1099 | [ fuzz (list int) "behaves like foldl if function always returns Continue" <| 1100 | \xs -> 1101 | stoppableFoldl (\n acc -> Continue (n + acc)) 0 xs 1102 | |> Expect.equal (List.foldl (\n acc -> n + acc) 0 xs) 1103 | , test "simple example" <| 1104 | \() -> 1105 | stoppableFoldl 1106 | (\n acc -> 1107 | if acc >= 50 then 1108 | Stop acc 1109 | 1110 | else 1111 | Continue (n + acc) 1112 | ) 1113 | 0 1114 | (List.range 1 1000) 1115 | |> Expect.equal 55 1116 | , test "after Stop, the function is not called anymore" <| 1117 | let 1118 | throwRangeErrorException : () -> a 1119 | throwRangeErrorException () = 1120 | preventTailCallOptimization () 1121 | 1122 | preventTailCallOptimization : () -> a 1123 | preventTailCallOptimization () = 1124 | throwRangeErrorException () 1125 | in 1126 | \() -> 1127 | stoppableFoldl 1128 | (\n acc -> 1129 | if n < 50 then 1130 | Continue n 1131 | 1132 | else if n == 50 then 1133 | Stop n 1134 | 1135 | else 1136 | throwRangeErrorException () 1137 | ) 1138 | 0 1139 | (List.range 1 1000) 1140 | |> Expect.equal 50 1141 | ] 1142 | ] 1143 | -------------------------------------------------------------------------------- /src/List/Extra.elm: -------------------------------------------------------------------------------- 1 | module List.Extra exposing 2 | ( 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 3 | , intercalate, transpose, subsequences, permutations, interweave, cartesianProduct, uniquePairs 4 | , foldl1, foldr1, indexedFoldl, indexedFoldr, Step(..), stoppableFoldl 5 | , scanl, scanl1, scanr, scanr1, mapAccuml, mapAccumr, unfoldr, iterate, initialize, cycle, reverseRange 6 | , splitAt, splitWhen, takeWhileRight, dropWhileRight, span, break, stripPrefix, group, groupWhile, inits, tails, select, selectSplit, gatherEquals, gatherEqualsBy, gatherWith, subsequencesNonEmpty, frequencies 7 | , isPrefixOf, isSuffixOf, isInfixOf, isSubsequenceOf, isPermutationOf 8 | , notMember, find, elemIndex, elemIndices, findIndex, findIndices, findMap, count 9 | , zip, zip3 10 | , lift2, lift3, lift4 11 | , groupsOf, groupsOfWithStep, groupsOfVarying, greedyGroupsOf, greedyGroupsOfWithStep 12 | , joinOn 13 | ) 14 | 15 | {-| Convenience functions for working with List 16 | 17 | 18 | # Basics 19 | 20 | @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 21 | 22 | 23 | # List transformations 24 | 25 | @docs intercalate, transpose, subsequences, permutations, interweave, cartesianProduct, uniquePairs 26 | 27 | 28 | # Folds 29 | 30 | @docs foldl1, foldr1, indexedFoldl, indexedFoldr, Step, stoppableFoldl 31 | 32 | 33 | # Building lists 34 | 35 | @docs scanl, scanl1, scanr, scanr1, mapAccuml, mapAccumr, unfoldr, iterate, initialize, cycle, reverseRange 36 | 37 | 38 | # Sublists 39 | 40 | @docs splitAt, splitWhen, takeWhileRight, dropWhileRight, span, break, stripPrefix, group, groupWhile, inits, tails, select, selectSplit, gatherEquals, gatherEqualsBy, gatherWith, subsequencesNonEmpty, frequencies 41 | 42 | 43 | # Predicates 44 | 45 | @docs isPrefixOf, isSuffixOf, isInfixOf, isSubsequenceOf, isPermutationOf 46 | 47 | 48 | # Searching 49 | 50 | @docs notMember, find, elemIndex, elemIndices, findIndex, findIndices, findMap, count 51 | 52 | 53 | # Zipping 54 | 55 | @docs zip, zip3 56 | 57 | 58 | # Lift functions onto multiple lists of arguments 59 | 60 | @docs lift2, lift3, lift4 61 | 62 | 63 | # Split to groups of given size 64 | 65 | @docs groupsOf, groupsOfWithStep, groupsOfVarying, greedyGroupsOf, greedyGroupsOfWithStep 66 | 67 | 68 | # Joins 69 | 70 | @docs joinOn 71 | 72 | -} 73 | 74 | import List exposing (..) 75 | import Tuple exposing (first, second) 76 | 77 | 78 | {-| Extract the last element of a list. 79 | 80 | last [ 1, 2, 3 ] 81 | --> Just 3 82 | 83 | last [] 84 | --> Nothing 85 | 86 | -} 87 | last : List a -> Maybe a 88 | last items = 89 | case items of 90 | [] -> 91 | Nothing 92 | 93 | [ x ] -> 94 | Just x 95 | 96 | _ :: rest -> 97 | last rest 98 | 99 | 100 | {-| Return all elements of the list except the last one. 101 | 102 | init [ 1, 2, 3 ] 103 | --> Just [ 1, 2 ] 104 | 105 | init [] 106 | --> Nothing 107 | 108 | -} 109 | init : List a -> Maybe (List a) 110 | init items = 111 | case items of 112 | [] -> 113 | Nothing 114 | 115 | nonEmptyList -> 116 | nonEmptyList 117 | |> List.reverse 118 | |> List.tail 119 | |> Maybe.map List.reverse 120 | 121 | 122 | {-| Returns `Just` the element at the given index in the list, 123 | or `Nothing` if the index is out of range. 124 | -} 125 | getAt : Int -> List a -> Maybe a 126 | getAt idx xs = 127 | if idx < 0 then 128 | Nothing 129 | 130 | else 131 | List.head <| List.drop idx xs 132 | 133 | 134 | {-| Returns a list of repeated applications of `f`. If `f` returns `Nothing` 135 | the iteration will stop. If it returns `Just y` then `y` will be added to the 136 | list and the iteration will continue with `f y`. 137 | 138 | collatz : Int -> Maybe Int 139 | collatz n = 140 | if n == 1 then 141 | Nothing 142 | else 143 | Just <| 144 | if modBy 2 n == 0 then 145 | n // 2 146 | else 147 | 3 * n + 1 148 | 149 | iterate collatz 13 150 | --> [13,40,20,10,5,16,8,4,2,1] 151 | 152 | -} 153 | iterate : (a -> Maybe a) -> a -> List a 154 | iterate f x = 155 | iterateHelp f x [] |> List.reverse 156 | 157 | 158 | iterateHelp : (a -> Maybe a) -> a -> List a -> List a 159 | iterateHelp f x acc = 160 | case f x of 161 | Just x_ -> 162 | iterateHelp f x_ (x :: acc) 163 | 164 | Nothing -> 165 | x :: acc 166 | 167 | 168 | {-| Initialize a list of some length with some function. 169 | 170 | `initialize n f` creates a list of length `n` with the element at index `i` initialized to the result of `f i`. 171 | 172 | -} 173 | initialize : Int -> (Int -> a) -> List a 174 | initialize n f = 175 | let 176 | step i acc = 177 | if i < 0 then 178 | acc 179 | 180 | else 181 | step (i - 1) (f i :: acc) 182 | in 183 | step (n - 1) [] 184 | 185 | 186 | {-| Creates a list of the given length whose elements are obtained by cycling 187 | through the elements of the given list. If the given list is empty, the 188 | resulting list will be empty. 189 | 190 | cycle 6 [ 4, 7, 8 ] 191 | --> [ 4, 7, 8, 4, 7, 8 ] 192 | 193 | cycle 4 [ 'a', 'b', 'c' ] 194 | --> [ 'a', 'b', 'c', 'a' ] 195 | 196 | cycle 9001 [] 197 | --> [] 198 | 199 | cycle 2 [ 1, 2, 3, 4, 5 ] 200 | --> [ 1, 2 ] 201 | 202 | -} 203 | cycle : Int -> List a -> List a 204 | cycle len list = 205 | let 206 | cycleLength = 207 | List.length list 208 | in 209 | if cycleLength == 0 || cycleLength == len then 210 | list 211 | 212 | else if cycleLength < len then 213 | List.reverse 214 | (reverseAppend 215 | (List.take (remainderBy cycleLength len) list) 216 | (cycleHelp [] (len // cycleLength) list) 217 | ) 218 | 219 | else 220 | List.take len list 221 | 222 | 223 | cycleHelp : List a -> Int -> List a -> List a 224 | cycleHelp acc n list = 225 | if n > 0 then 226 | cycleHelp (reverseAppend list acc) (n - 1) list 227 | 228 | else 229 | acc 230 | 231 | 232 | {-| Create a list of numbers, every element decreasing by one. 233 | You give the highest and lowest number that should be in the list. 234 | More efficient than calling `List.reverse (List.range lo hi)` 235 | 236 | range 6 3 == [ 6, 5, 4, 3 ] 237 | 238 | range 3 3 == [ 3 ] 239 | 240 | range 3 6 == [] 241 | 242 | -} 243 | reverseRange : Int -> Int -> List Int 244 | reverseRange = 245 | let 246 | helper : List Int -> Int -> Int -> List Int 247 | helper list high low = 248 | if high >= low then 249 | helper (low :: list) high (low + 1) 250 | 251 | else 252 | list 253 | in 254 | helper [] 255 | 256 | 257 | {-| 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. 258 | 259 | uncons [1,2,3] 260 | --> Just (1, [2,3]) 261 | 262 | uncons [] 263 | --> Nothing 264 | 265 | -} 266 | uncons : List a -> Maybe ( a, List a ) 267 | uncons list = 268 | case list of 269 | [] -> 270 | Nothing 271 | 272 | first :: rest -> 273 | Just ( first, rest ) 274 | 275 | 276 | {-| 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. 277 | 278 | unconsLast [1,2,3] 279 | --> Just (3, [1,2]) 280 | 281 | unconsLast [] 282 | --> Nothing 283 | 284 | -} 285 | unconsLast : List a -> Maybe ( a, List a ) 286 | unconsLast list = 287 | case List.reverse list of 288 | [] -> 289 | Nothing 290 | 291 | last_ :: rest -> 292 | ( last_, List.reverse rest ) 293 | |> Just 294 | 295 | 296 | {-| Find the first maximum element in a list using a comparable transformation 297 | -} 298 | maximumBy : (a -> comparable) -> List a -> Maybe a 299 | maximumBy f ls = 300 | let 301 | maxBy : a -> ( a, comparable ) -> ( a, comparable ) 302 | maxBy x (( _, fy ) as max) = 303 | let 304 | fx : comparable 305 | fx = 306 | f x 307 | in 308 | if fx > fy then 309 | ( x, fx ) 310 | 311 | else 312 | max 313 | in 314 | case ls of 315 | [ l_ ] -> 316 | Just l_ 317 | 318 | l_ :: ls_ -> 319 | Just <| first <| foldl maxBy ( l_, f l_ ) ls_ 320 | 321 | _ -> 322 | Nothing 323 | 324 | 325 | {-| Find the first maximum element in a list using a comparison function 326 | 327 | maximumWith compare [] 328 | --> Nothing 329 | 330 | maximumWith 331 | (\x y -> compare x.val y.val) 332 | [{id=1, val=1}, {id=2, val=2}, {id=3,val=2}] 333 | --> Just { id = 2, val = 2 } 334 | 335 | -} 336 | maximumWith : (a -> a -> Order) -> List a -> Maybe a 337 | maximumWith comparator list = 338 | foldl1 339 | (\x y -> 340 | case comparator x y of 341 | GT -> 342 | x 343 | 344 | _ -> 345 | y 346 | ) 347 | list 348 | 349 | 350 | {-| Find the first minimum element in a list using a comparable transformation 351 | -} 352 | minimumBy : (a -> comparable) -> List a -> Maybe a 353 | minimumBy f ls = 354 | let 355 | minBy : a -> ( a, comparable ) -> ( a, comparable ) 356 | minBy x (( _, fy ) as min) = 357 | let 358 | fx : comparable 359 | fx = 360 | f x 361 | in 362 | if fx < fy then 363 | ( x, fx ) 364 | 365 | else 366 | min 367 | in 368 | case ls of 369 | [ l_ ] -> 370 | Just l_ 371 | 372 | l_ :: ls_ -> 373 | Just <| first <| foldl minBy ( l_, f l_ ) ls_ 374 | 375 | _ -> 376 | Nothing 377 | 378 | 379 | {-| Find the first minimum element in a list using a comparison function 380 | 381 | minimumWith compare [] 382 | --> Nothing 383 | minimumWith 384 | (\x y -> compare x.val y.val) 385 | [{id=1, val=2}, {id=2, val=1}, {id=3,val=1}] 386 | --> Just { id = 2, val = 1 } 387 | 388 | -} 389 | minimumWith : (a -> a -> Order) -> List a -> Maybe a 390 | minimumWith comparator list = 391 | foldl1 392 | (\x y -> 393 | case comparator x y of 394 | LT -> 395 | x 396 | 397 | _ -> 398 | y 399 | ) 400 | list 401 | 402 | 403 | {-| Take elements in order as long as the predicate evaluates to `True` 404 | -} 405 | takeWhile : (a -> Bool) -> List a -> List a 406 | takeWhile predicate = 407 | let 408 | takeWhileMemo memo list = 409 | case list of 410 | [] -> 411 | List.reverse memo 412 | 413 | x :: xs -> 414 | if predicate x then 415 | takeWhileMemo (x :: memo) xs 416 | 417 | else 418 | List.reverse memo 419 | in 420 | takeWhileMemo [] 421 | 422 | 423 | {-| Drop elements in order as long as the predicate evaluates to `True` 424 | -} 425 | dropWhile : (a -> Bool) -> List a -> List a 426 | dropWhile predicate list = 427 | case list of 428 | [] -> 429 | [] 430 | 431 | x :: xs -> 432 | if predicate x then 433 | dropWhile predicate xs 434 | 435 | else 436 | list 437 | 438 | 439 | {-| Remove duplicate values, keeping the first instance of each element which appears more than once. 440 | 441 | unique [ 0, 1, 1, 0, 1 ] 442 | --> [ 0, 1 ] 443 | 444 | -} 445 | unique : List a -> List a 446 | unique list = 447 | uniqueHelp identity [] list [] 448 | 449 | 450 | {-| 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. 451 | -} 452 | uniqueBy : (a -> b) -> List a -> List a 453 | uniqueBy f list = 454 | uniqueHelp f [] list [] 455 | 456 | 457 | {-| Indicate if list has duplicate values. 458 | 459 | allDifferent [ 0, 1, 1, 0, 1 ] 460 | --> False 461 | 462 | allDifferent [ 0, 1, 2] 463 | --> True 464 | 465 | -} 466 | allDifferent : List a -> Bool 467 | allDifferent list = 468 | allDifferentBy identity list 469 | 470 | 471 | {-| Indicate if list has duplicate values when supplied function are applied on each values. 472 | -} 473 | allDifferentBy : (a -> b) -> List a -> Bool 474 | allDifferentBy f list = 475 | List.length list == List.length (uniqueBy f list) 476 | 477 | 478 | uniqueHelp : (a -> b) -> List b -> List a -> List a -> List a 479 | uniqueHelp f existing remaining accumulator = 480 | case remaining of 481 | [] -> 482 | List.reverse accumulator 483 | 484 | first :: rest -> 485 | let 486 | computedFirst = 487 | f first 488 | in 489 | if List.member computedFirst existing then 490 | uniqueHelp f existing rest accumulator 491 | 492 | else 493 | uniqueHelp f (computedFirst :: existing) rest (first :: accumulator) 494 | 495 | 496 | {-| Map functions taking multiple arguments over multiple lists. Each list should be of the same length. 497 | 498 | toIntFunctions : List (Float -> Int) 499 | toIntFunctions = 500 | [ round 501 | , floor 502 | , ceiling 503 | , truncate 504 | ] 505 | 506 | toIntFunctions 507 | |> andMap [ -1.5, -1.5, -1.5, -1.5 ] 508 | --> [ -1, -2, -1, -1 ] 509 | 510 | 511 | math : List (Int -> Int) 512 | math = 513 | [ (+) 1 514 | , (*) 2 515 | , (*) 3 >> (+) 1 516 | ] 517 | 518 | math 519 | |> andMap [ 1, 2, 3 ] 520 | --> [ 2, 4, 10 ] 521 | 522 | -} 523 | andMap : List a -> List (a -> b) -> List b 524 | andMap l fl = 525 | map2 (<|) fl l 526 | 527 | 528 | {-| Equivalent to `concatMap`. For example, suppose you want to have a cartesian product of [1,2] and [3,4]: 529 | 530 | [ 1, 2 ] 531 | |> andThen 532 | (\x -> 533 | [ 3, 4 ] 534 | |> andThen (\y -> [ ( x, y ) ]) 535 | ) 536 | --> [ ( 1, 3 ), ( 1, 4 ), ( 2, 3 ), ( 2, 4 ) ] 537 | 538 | Now suppose we want to have a cartesian product between the first list and the second list and its doubles: 539 | 540 | [ 1, 2 ] 541 | |> andThen 542 | (\x -> 543 | [ 3, 4 ] 544 | |> andThen 545 | (\y -> 546 | [ y, y * 2 ] 547 | |> andThen (\z -> [ ( x, z ) ]) 548 | ) 549 | ) 550 | --> [ ( 1, 3 ), ( 1, 6 ), ( 1, 4 ), ( 1, 8 ), ( 2, 3 ), ( 2, 6 ), ( 2, 4 ), ( 2, 8 )] 551 | 552 | Advanced functional programmers will recognize this as the implementation of bind operator (>>=) for lists from the `Monad` typeclass. 553 | 554 | -} 555 | andThen : (a -> List b) -> List a -> List b 556 | andThen = 557 | concatMap 558 | 559 | 560 | {-| `reverseMap f xs` gives the same result as `List.reverse (List.map f xs)`, 561 | but is tail-recursive and slightly more efficient. 562 | 563 | reverseMap sqrt [ 1, 4, 9 ] 564 | --> [ 3, 2, 1 ] 565 | 566 | -} 567 | reverseMap : (a -> b) -> List a -> List b 568 | reverseMap f xs = 569 | foldl (\x acc -> f x :: acc) [] xs 570 | 571 | 572 | {-| `reverseMap f xs` gives the same result as `List.reverse (List.map f xs)`, 573 | but is tail-recursive and slightly more efficient. 574 | 575 | reverseFilter (\x -> x > 5) [ 1, 4, 9, 16] 576 | --> [ 16, 9 ] 577 | 578 | -} 579 | reverseFilter : (a -> Bool) -> List a -> List a 580 | reverseFilter isGood xs = 581 | foldl 582 | (\x acc -> 583 | if isGood x then 584 | x :: acc 585 | 586 | else 587 | acc 588 | ) 589 | [] 590 | xs 591 | 592 | 593 | {-| Negation of `member`. 594 | 595 | notMember 1 [ 1, 2, 3 ] 596 | --> False 597 | 598 | notMember 4 [ 1, 2, 3 ] 599 | --> True 600 | 601 | -} 602 | notMember : a -> List a -> Bool 603 | notMember x = 604 | not << member x 605 | 606 | 607 | {-| Find the first element that satisfies a predicate and return 608 | Just that element. If none match, return Nothing. 609 | 610 | find (\num -> num > 5) [ 2, 4, 6, 8 ] 611 | --> Just 6 612 | 613 | -} 614 | find : (a -> Bool) -> List a -> Maybe a 615 | find predicate list = 616 | case list of 617 | [] -> 618 | Nothing 619 | 620 | first :: rest -> 621 | if predicate first then 622 | Just first 623 | 624 | else 625 | find predicate rest 626 | 627 | 628 | {-| Return the index of the first occurrence of the element. Otherwise, return `Nothing`. Indexing starts from 0. 629 | 630 | elemIndex 1 [ 1, 2, 3 ] 631 | --> Just 0 632 | 633 | elemIndex 4 [ 1, 2, 3 ] 634 | --> Nothing 635 | 636 | elemIndex 1 [ 1, 2, 1 ] 637 | --> Just 0 638 | 639 | -} 640 | elemIndex : a -> List a -> Maybe Int 641 | elemIndex x = 642 | findIndex ((==) x) 643 | 644 | 645 | {-| Return all indices of occurrences of the element. If element is not found, return empty list. Indexing starts from 0. 646 | 647 | elemIndices 1 [ 1, 2, 3 ] 648 | --> [ 0 ] 649 | 650 | elemIndices 4 [ 1, 2, 3 ] 651 | --> [] 652 | 653 | elemIndices 1 [ 1, 2, 1 ] 654 | --> [ 0, 2 ] 655 | 656 | -} 657 | elemIndices : a -> List a -> List Int 658 | elemIndices x = 659 | findIndices ((==) x) 660 | 661 | 662 | {-| Take a predicate and a list, return the index of the first element that satisfies the predicate. Otherwise, return `Nothing`. Indexing starts from 0. 663 | 664 | isEven : Int -> Bool 665 | isEven i = 666 | modBy 2 i == 0 667 | 668 | findIndex isEven [ 1, 2, 3 ] 669 | --> Just 1 670 | 671 | findIndex isEven [ 1, 3, 5 ] 672 | --> Nothing 673 | 674 | findIndex isEven [ 1, 2, 4 ] 675 | --> Just 1 676 | 677 | -} 678 | findIndex : (a -> Bool) -> List a -> Maybe Int 679 | findIndex = 680 | findIndexHelp 0 681 | 682 | 683 | findIndexHelp : Int -> (a -> Bool) -> List a -> Maybe Int 684 | findIndexHelp index predicate list = 685 | case list of 686 | [] -> 687 | Nothing 688 | 689 | x :: xs -> 690 | if predicate x then 691 | Just index 692 | 693 | else 694 | findIndexHelp (index + 1) predicate xs 695 | 696 | 697 | {-| Take a predicate and a list, return indices of all elements satisfying the predicate. Otherwise, return empty list. Indexing starts from 0. 698 | 699 | isEven : Int -> Bool 700 | isEven i = 701 | modBy 2 i == 0 702 | 703 | findIndices isEven [ 1, 2, 3 ] 704 | --> [ 1 ] 705 | 706 | findIndices isEven [ 1, 3, 5 ] 707 | --> [] 708 | 709 | findIndices isEven [ 1, 2, 4 ] 710 | --> [ 1, 2 ] 711 | 712 | -} 713 | findIndices : (a -> Bool) -> List a -> List Int 714 | findIndices predicate = 715 | let 716 | consIndexIf index x acc = 717 | if predicate x then 718 | index :: acc 719 | 720 | else 721 | acc 722 | in 723 | indexedFoldr consIndexIf [] 724 | 725 | 726 | {-| 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. 727 | 728 | mapOverFive : Int -> Maybe Int 729 | mapOverFive num = 730 | if num > 5 then 731 | Just (num * 2) 732 | else 733 | Nothing 734 | 735 | findMap mapOverFive [2, 4, 6, 8] 736 | --> Just 12 737 | 738 | This is particularly useful in cases where you have a complex type in a list, and you need to pick out the the first one 739 | 740 | type alias HouseModel = 741 | {} 742 | 743 | type Property 744 | = Rental 745 | | House HouseModel 746 | | Commercial 747 | 748 | toHouse : Property -> Maybe HouseModel 749 | toHouse property = 750 | case property of 751 | House house -> 752 | Just house 753 | 754 | _ -> 755 | Nothing 756 | 757 | viewFirstHomeOfInterest : Viewer -> List Property -> Html msg 758 | viewFirstHomeOfInterest viewer propertiesQuery = 759 | propertiesQuery 760 | |> findMap toHouse 761 | |> Maybe.map homeView 762 | |> Maybe.withDefault noHomeView 763 | 764 | -} 765 | findMap : (a -> Maybe b) -> List a -> Maybe b 766 | findMap f list = 767 | case list of 768 | [] -> 769 | Nothing 770 | 771 | a :: tail -> 772 | case f a of 773 | Just b -> 774 | Just b 775 | 776 | Nothing -> 777 | findMap f tail 778 | 779 | 780 | {-| Returns the number of elements in a list that satisfy a given predicate. 781 | Equivalent to `List.length (List.filter pred list)` but more efficient. 782 | 783 | count 784 | (modBy 2 >> (==) 1) [ 1, 2, 3, 4, 5, 6, 7 ] 785 | --> 4 786 | 787 | count 788 | ((==) "yeah") 789 | [ "She", "loves", "you", "yeah", "yeah", "yeah" ] 790 | --> 3 791 | 792 | -} 793 | count : (a -> Bool) -> List a -> Int 794 | count predicate = 795 | List.foldl 796 | (\x acc -> 797 | if predicate x then 798 | acc + 1 799 | 800 | else 801 | acc 802 | ) 803 | 0 804 | 805 | 806 | {-| Replace all values that satisfy a predicate with a replacement value. 807 | -} 808 | setIf : (a -> Bool) -> a -> List a -> List a 809 | setIf predicate replacement list = 810 | updateIf predicate (always replacement) list 811 | 812 | 813 | {-| Replace all values that satisfy a predicate by calling an update function. 814 | -} 815 | updateIf : (a -> Bool) -> (a -> a) -> List a -> List a 816 | updateIf predicate update list = 817 | List.map 818 | (\item -> 819 | if predicate item then 820 | update item 821 | 822 | else 823 | item 824 | ) 825 | list 826 | 827 | 828 | {-| Replace a value at a specific index by calling an update function. Return the original list if the index is out of range. 829 | 830 | updateAt 0 ((+) 1) [ 1, 2, 3 ] 831 | --> [ 2, 2, 3 ] 832 | 833 | See also `updateIfIndex`. 834 | 835 | -} 836 | updateAt : Int -> (a -> a) -> List a -> List a 837 | updateAt index fn list = 838 | if index < 0 then 839 | list 840 | 841 | else 842 | let 843 | tail : List a 844 | tail = 845 | List.drop index list 846 | in 847 | case tail of 848 | x :: xs -> 849 | List.take index list ++ fn x :: xs 850 | 851 | [] -> 852 | list 853 | 854 | 855 | {-| Replace a value at an index that satisfies a predicate, by calling an update function. 856 | 857 | updateIfIndex ((==) 2) ((+) 1) [ 1, 2, 3 ] 858 | --> [ 1, 2, 4 ] 859 | 860 | See also `updateAt`. 861 | 862 | -} 863 | updateIfIndex : (Int -> Bool) -> (a -> a) -> List a -> List a 864 | updateIfIndex predicate update list = 865 | List.indexedMap 866 | (\i x -> 867 | if predicate i then 868 | update x 869 | 870 | else 871 | x 872 | ) 873 | list 874 | 875 | 876 | {-| Remove the first occurrence of a value from a list. 877 | -} 878 | remove : a -> List a -> List a 879 | remove x xs = 880 | removeHelp xs x xs [] 881 | 882 | 883 | removeHelp : List a -> a -> List a -> List a -> List a 884 | removeHelp list x xs previousElements = 885 | case xs of 886 | [] -> 887 | list 888 | 889 | y :: ys -> 890 | if x == y then 891 | reverseAppend previousElements ys 892 | 893 | else 894 | removeHelp list x ys (y :: previousElements) 895 | 896 | 897 | {-| Set a value in a list by index. Return the original list if the index is out of range. 898 | 899 | setAt 0 42 [ 1, 2, 3 ] 900 | --> [ 42, 2, 3 ] 901 | 902 | -} 903 | setAt : Int -> a -> List a -> List a 904 | setAt index value = 905 | updateAt index (always value) 906 | 907 | 908 | {-| Similar to List.sortWith, this sorts values with a custom comparison function. 909 | Unlike List.sortWith, this sort is guaranteed to be a stable sort. 910 | Note that List.sortWith is faster and is preferred if sort stability is not required. 911 | -} 912 | stableSortWith : (a -> a -> Basics.Order) -> List a -> List a 913 | stableSortWith pred list = 914 | let 915 | listWithIndex = 916 | List.indexedMap (\i a -> ( a, i )) list 917 | 918 | predWithIndex ( a1, i1 ) ( a2, i2 ) = 919 | let 920 | result = 921 | pred a1 a2 922 | in 923 | case result of 924 | Basics.EQ -> 925 | Basics.compare i1 i2 926 | 927 | _ -> 928 | result 929 | in 930 | List.sortWith predWithIndex listWithIndex |> List.map first 931 | 932 | 933 | {-| Swap two values in a list by index. Return the original list if the index is out of range. 934 | If the same index is supplied twice the operation has no effect. 935 | 936 | swapAt 1 2 [ 1, 2, 3 ] 937 | --> [ 1, 3, 2 ] 938 | 939 | -} 940 | swapAt : Int -> Int -> List a -> List a 941 | swapAt index1 index2 l = 942 | if index1 == index2 || index1 < 0 then 943 | l 944 | 945 | else if index1 > index2 then 946 | swapAt index2 index1 l 947 | 948 | else 949 | let 950 | ( part1, tail1 ) = 951 | splitAt index1 l 952 | 953 | ( head2, tail2 ) = 954 | splitAt (index2 - index1) tail1 955 | in 956 | case ( uncons head2, uncons tail2 ) of 957 | ( Just ( value1, part2 ), Just ( value2, part3 ) ) -> 958 | List.concat [ part1, value2 :: part2, value1 :: part3 ] 959 | 960 | _ -> 961 | l 962 | 963 | 964 | {-| Remove the element at an index from a list. Return the original list if the index is out of range. 965 | 966 | removeAt 0 [ 1, 2, 3 ] 967 | --> [ 2, 3 ] 968 | 969 | See also `removeIfIndex`. 970 | 971 | -} 972 | removeAt : Int -> List a -> List a 973 | removeAt index l = 974 | if index < 0 then 975 | l 976 | 977 | else 978 | case drop index l of 979 | [] -> 980 | l 981 | 982 | _ :: rest -> 983 | take index l ++ rest 984 | 985 | 986 | {-| Remove an element at an index that satisfies a predicate. 987 | 988 | removeIfIndex ((==) 2) [ 1, 2, 3 ] 989 | --> [ 1, 2 ] 990 | 991 | See also `removeAt`. 992 | 993 | -} 994 | removeIfIndex : (Int -> Bool) -> List a -> List a 995 | removeIfIndex predicate = 996 | indexedFoldr 997 | (\index item acc -> 998 | if predicate index then 999 | acc 1000 | 1001 | else 1002 | item :: acc 1003 | ) 1004 | [] 1005 | 1006 | 1007 | {-| Take a predicate and a list, and return a list that contains elements which fails to satisfy the predicate. 1008 | This is equivalent to `List.filter (not << predicate) list`. 1009 | 1010 | isEven : Int -> Bool 1011 | isEven i = 1012 | modBy 2 i == 0 1013 | 1014 | filterNot isEven [ 1, 2, 3, 4 ] 1015 | --> [ 1, 3 ] 1016 | 1017 | -} 1018 | filterNot : (a -> Bool) -> List a -> List a 1019 | filterNot pred list = 1020 | List.filter (not << pred) list 1021 | 1022 | 1023 | {-| 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)`. 1024 | 1025 | intercalate [ 0, 0 ] [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ] ] 1026 | --> [ 1, 2, 0, 0, 3, 4, 0, 0, 5, 6 ] 1027 | 1028 | -} 1029 | intercalate : List a -> List (List a) -> List a 1030 | intercalate xs = 1031 | concat << intersperse xs 1032 | 1033 | 1034 | {-| Transpose rows and columns of the list of lists. 1035 | 1036 | transpose [ [ 1, 2, 3 ], [ 4, 5, 6 ] ] 1037 | --> [ [ 1, 4 ], [ 2, 5 ], [ 3, 6 ] ] 1038 | 1039 | transpose [ [ 10, 11 ], [ 20, 40 ], [ 30, 31, 32, 400 ] ] 1040 | --> [ [ 10, 20, 30 ], [ 11, 40, 31 ] ] 1041 | 1042 | -} 1043 | transpose : List (List a) -> List (List a) 1044 | transpose listOfLists = 1045 | List.foldr (List.map2 (::)) (List.repeat (rowsLength listOfLists) []) listOfLists 1046 | 1047 | 1048 | rowsLength : List (List a) -> Int 1049 | rowsLength listOfLists = 1050 | case listOfLists of 1051 | [] -> 1052 | 0 1053 | 1054 | x :: _ -> 1055 | List.length x 1056 | 1057 | 1058 | {-| Return the list of all subsequences of a list. 1059 | 1060 | subsequences [ 1, 2, 3 ] 1061 | --> [ [], [ 1 ], [ 2 ], [ 1, 2 ], [ 3 ], [ 1, 3 ], [ 2, 3 ], [ 1, 2, 3 ] ] 1062 | 1063 | -} 1064 | subsequences : List a -> List (List a) 1065 | subsequences xs = 1066 | [] :: subsequencesHelp xs 1067 | 1068 | 1069 | {-| Return the list of all subsequences of the argument, except for the empty list. 1070 | 1071 | subsequencesNonEmpty [ 1, 2, 3 ] 1072 | == [ [ 1 ], [ 2 ], [ 1, 2 ], [ 3 ], [ 1, 3 ], [ 2, 3 ], [ 1, 2, 3 ] ] 1073 | 1074 | -} 1075 | subsequencesHelp : List a -> List (List a) 1076 | subsequencesHelp list = 1077 | case list of 1078 | [] -> 1079 | [] 1080 | 1081 | first :: rest -> 1082 | let 1083 | f ys r = 1084 | ys :: (first :: ys) :: r 1085 | in 1086 | [ first ] :: foldr f [] (subsequencesHelp rest) 1087 | 1088 | 1089 | {-| Return the list of all subsequences of the argument, except for the empty list. 1090 | 1091 | subsequencesNonEmpty [ 1, 2, 3 ] 1092 | == [ [ 1 ], [ 2 ], [ 1, 2 ], [ 3 ], [ 1, 3 ], [ 2, 3 ], [ 1, 2, 3 ] ] 1093 | 1094 | -} 1095 | subsequencesNonEmpty : List a -> List ( a, List a ) 1096 | subsequencesNonEmpty list = 1097 | case list of 1098 | [] -> 1099 | [] 1100 | 1101 | first :: rest -> 1102 | let 1103 | f : ( a, List a ) -> List ( a, List a ) -> List ( a, List a ) 1104 | f ( yf, ys ) r = 1105 | ( yf, ys ) :: ( first, yf :: ys ) :: r 1106 | in 1107 | ( first, [] ) :: foldr f [] (subsequencesNonEmpty rest) 1108 | 1109 | 1110 | {-| Return the list of of all permutations of a list. The result is in lexicographic order. 1111 | 1112 | permutations [ 1, 2, 3 ] 1113 | --> [ [ 1, 2, 3 ], [ 1, 3, 2 ], [ 2, 1, 3 ], [ 2, 3, 1 ], [ 3, 1, 2 ], [ 3, 2, 1 ] ] 1114 | 1115 | -} 1116 | permutations : List a -> List (List a) 1117 | permutations xs_ = 1118 | case xs_ of 1119 | [] -> 1120 | [ [] ] 1121 | 1122 | xs -> 1123 | let 1124 | f ( y, ys ) = 1125 | map ((::) y) (permutations ys) 1126 | in 1127 | concatMap f (select xs) 1128 | 1129 | 1130 | {-| Return a list that contains elements from the two provided, in alternate order. 1131 | If one list runs out of items, append the items from the remaining list. 1132 | 1133 | interweave [ 1, 3 ] [ 2, 4 ] 1134 | --> [ 1, 2, 3, 4 ] 1135 | 1136 | interweave [ 1, 3, 5, 7 ] [ 2, 4 ] 1137 | --> [ 1, 2, 3, 4, 5, 7 ] 1138 | 1139 | interweave [ 4, 9, 16 ] [ 2, 3, 5, 7 ] 1140 | --> [ 4, 2, 9, 3, 16, 5, 7 ] 1141 | 1142 | -} 1143 | interweave : List a -> List a -> List a 1144 | interweave = 1145 | interweaveHelp [] 1146 | 1147 | 1148 | interweaveHelp : List a -> List a -> List a -> List a 1149 | interweaveHelp acc list1 list2 = 1150 | case ( list1, list2 ) of 1151 | ( x :: xs, y :: ys ) -> 1152 | interweaveHelp (y :: x :: acc) xs ys 1153 | 1154 | ( [], _ ) -> 1155 | reverseAppend acc list2 1156 | 1157 | ( _, [] ) -> 1158 | reverseAppend acc list1 1159 | 1160 | 1161 | {-| Return the cartesian product of a list of lists. 1162 | If one list is empty, the result is an empty list. 1163 | If the list of lists is empty, the result is an empty singleton. 1164 | 1165 | cartesianProduct [ [ 1, 2 ], [ 3, 4, 5 ], [ 6 ] ] 1166 | --> [ [ 1, 3, 6 ], [ 1, 4, 6 ], [ 1, 5, 6 ], [ 2, 3, 6 ], [ 2, 4, 6 ], [ 2, 5, 6 ] ] 1167 | 1168 | cartesianProduct [ [ 1, 2 ] ] 1169 | --> [ [ 1 ], [ 2 ] ] 1170 | 1171 | cartesianProduct [ [ 1, 2 ], [], [ 6 ] ] 1172 | --> [] 1173 | 1174 | cartesianProduct [ [] ] 1175 | --> [] 1176 | 1177 | cartesianProduct [] 1178 | --> [ [] ] 1179 | 1180 | -} 1181 | cartesianProduct : List (List a) -> List (List a) 1182 | cartesianProduct ll = 1183 | case ll of 1184 | [] -> 1185 | [ [] ] 1186 | 1187 | xs :: xss -> 1188 | lift2 (::) xs (cartesianProduct xss) 1189 | 1190 | 1191 | {-| Return all ways to pair the elements of the list. 1192 | (Essentially, enumerate the possible "handshakes.") 1193 | 1194 | The order of the pair elements doesn't matter, so if `(1,2)` is a returned pair, 1195 | we don't return `(2,1)`. 1196 | 1197 | In more mathematical terms these are 2-combinations without repetition. 1198 | 1199 | uniquePairs [ 1, 2, 3, 4 ] 1200 | --> [ ( 1, 2 ), ( 1, 3 ), ( 1, 4 ), ( 2, 3 ), ( 2, 4 ), ( 3, 4 ) ] 1201 | 1202 | In this example, everybody shakes hands with three other people. 1203 | 1204 | -} 1205 | uniquePairs : List a -> List ( a, a ) 1206 | uniquePairs xs = 1207 | case xs of 1208 | [] -> 1209 | [] 1210 | 1211 | x :: xs_ -> 1212 | List.map (\y -> ( x, y )) xs_ ++ uniquePairs xs_ 1213 | 1214 | 1215 | reverseAppend : List a -> List a -> List a 1216 | reverseAppend list1 list2 = 1217 | List.foldl (::) list2 list1 1218 | 1219 | 1220 | {-| 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`. 1221 | 1222 | foldl1 (-) [ 1, 2, 3, 4 ] 1223 | --> Just 2 1224 | 1225 | foldl1 (++) [ "a", "b", "c" ] 1226 | --> Just "cba" 1227 | 1228 | foldl1 min [] 1229 | --> Nothing 1230 | 1231 | **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. 1232 | 1233 | -} 1234 | foldl1 : (a -> a -> a) -> List a -> Maybe a 1235 | foldl1 func list = 1236 | case list of 1237 | [] -> 1238 | Nothing 1239 | 1240 | x :: xs -> 1241 | Just (List.foldl func x xs) 1242 | 1243 | 1244 | {-| 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`. 1245 | 1246 | foldr1 (-) [ 1, 2, 3, 4 ] 1247 | --> Just -2 1248 | 1249 | foldr1 (++) [ "a", "b", "c" ] 1250 | --> Just "abc" 1251 | 1252 | foldr1 min [] 1253 | --> Nothing 1254 | 1255 | -} 1256 | foldr1 : (a -> a -> a) -> List a -> Maybe a 1257 | foldr1 func list = 1258 | foldl1 func (List.reverse list) 1259 | 1260 | 1261 | {-| 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`. 1262 | -} 1263 | indexedFoldl : (Int -> a -> b -> b) -> b -> List a -> b 1264 | indexedFoldl func acc list = 1265 | let 1266 | step : a -> ( Int, b ) -> ( Int, b ) 1267 | step x ( i, thisAcc ) = 1268 | ( i + 1, func i x thisAcc ) 1269 | in 1270 | second (List.foldl step ( 0, acc ) list) 1271 | 1272 | 1273 | {-| 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`. 1274 | -} 1275 | indexedFoldr : (Int -> a -> b -> b) -> b -> List a -> b 1276 | indexedFoldr func acc list = 1277 | let 1278 | step : a -> ( Int, b ) -> ( Int, b ) 1279 | step x ( i, thisAcc ) = 1280 | ( i - 1, func i x thisAcc ) 1281 | in 1282 | second (List.foldr step ( List.length list - 1, acc ) list) 1283 | 1284 | 1285 | {-| A custom type used for stoppable folds. 1286 | -} 1287 | type Step a 1288 | = Continue a 1289 | | Stop a 1290 | 1291 | 1292 | {-| A `foldl` that can stop early instead of traversing the whole list. 1293 | 1294 | stoppableFoldl 1295 | (\n acc -> 1296 | if acc >= 50 then 1297 | Stop acc 1298 | else 1299 | Continue (n + acc) 1300 | ) 1301 | 0 1302 | (List.range 1 10000) 1303 | --> 55 1304 | 1305 | -} 1306 | stoppableFoldl : (a -> b -> Step b) -> b -> List a -> b 1307 | stoppableFoldl func acc list = 1308 | case list of 1309 | [] -> 1310 | acc 1311 | 1312 | x :: xs -> 1313 | case func x acc of 1314 | Continue newAcc -> 1315 | stoppableFoldl func newAcc xs 1316 | 1317 | Stop finalAcc -> 1318 | finalAcc 1319 | 1320 | 1321 | {-| Reduce a list from the left, building up all of the intermediate results into a list. 1322 | 1323 | scanl (+) 0 [ 1, 2, 3, 4 ] 1324 | --> [ 0, 1, 3, 6, 10 ] 1325 | 1326 | -} 1327 | scanl : (a -> b -> b) -> b -> List a -> List b 1328 | scanl f b xs = 1329 | let 1330 | scan1 x accAcc = 1331 | case accAcc of 1332 | acc :: _ -> 1333 | f x acc :: accAcc 1334 | 1335 | [] -> 1336 | [] 1337 | 1338 | -- impossible 1339 | in 1340 | reverse (foldl scan1 [ b ] xs) 1341 | 1342 | 1343 | {-| `scanl1` is a variant of `scanl` that has no starting value argument. 1344 | 1345 | Compare: 1346 | 1347 | scanl (+) 0 [ 1, 2, 3 ] 1348 | --> [ 0, 1, 3, 6 ] 1349 | 1350 | scanl1 (+) [ 1, 2, 3 ] 1351 | --> [ 1, 3, 6 ] 1352 | 1353 | scanl (-) 0 [ 1, 2, 3 ] 1354 | --> [ 0, 1, 1, 2 ] 1355 | 1356 | scanl1 (-) [ 1, 2, 3 ] 1357 | --> [ 1, 1, 2 ] 1358 | 1359 | -} 1360 | scanl1 : (a -> a -> a) -> List a -> List a 1361 | scanl1 f xs_ = 1362 | case xs_ of 1363 | [] -> 1364 | [] 1365 | 1366 | x :: xs -> 1367 | scanl f x xs 1368 | 1369 | 1370 | {-| `scanr` is a right-to-left dual of `scanl`. Note that: 1371 | 1372 | head (scanr f z xs) == foldr f z xs 1373 | 1374 | Examples: 1375 | 1376 | scanr (+) 0 [ 1, 2, 3 ] 1377 | --> [ 6, 5, 3, 0 ] 1378 | 1379 | scanr (-) 0 [ 1, 2, 3 ] 1380 | --> [ 2, -1, 3, 0 ] 1381 | 1382 | -} 1383 | scanr : (a -> b -> b) -> b -> List a -> List b 1384 | scanr f acc xs_ = 1385 | case xs_ of 1386 | [] -> 1387 | [ acc ] 1388 | 1389 | x :: xs -> 1390 | case scanr f acc xs of 1391 | (q :: _) as qs -> 1392 | f x q :: qs 1393 | 1394 | [] -> 1395 | [] 1396 | 1397 | 1398 | {-| `scanr1` is a variant of `scanr` that has no starting value argument. 1399 | 1400 | scanr1 (+) [ 1, 2, 3 ] 1401 | --> [ 6, 5, 3 ] 1402 | 1403 | scanr1 (-) [ 1, 2, 3 ] 1404 | --> [ 2, -1, 3 ] 1405 | 1406 | -} 1407 | scanr1 : (a -> a -> a) -> List a -> List a 1408 | scanr1 f xs_ = 1409 | case xs_ of 1410 | [] -> 1411 | [] 1412 | 1413 | [ x ] -> 1414 | [ x ] 1415 | 1416 | x :: xs -> 1417 | case scanr1 f xs of 1418 | (q :: _) as qs -> 1419 | f x q :: qs 1420 | 1421 | [] -> 1422 | [] 1423 | 1424 | 1425 | {-| The mapAccuml function behaves like a combination of map and foldl; it applies a 1426 | function to each element of a list, passing an accumulating parameter from left to right, 1427 | and returning a final value of this accumulator together with the new list. 1428 | 1429 | mapAccuml f a0 [ x1, x2, x3 ] == ( a3, [ y1, y2, y3 ] ) 1430 | 1431 | -- x1 x2 x3 1432 | -- | | | 1433 | -- a0 -- f --- f --- f -> a3 1434 | -- | | | 1435 | -- y1 y2 y3 1436 | 1437 | Add a running total to a list of numbers: 1438 | 1439 | mapAccuml (\a x -> ( a + x, ( x, a + x ) )) 0 [ 2, 4, 8 ] 1440 | --> ( 14, [ ( 2, 2 ), ( 4, 6 ), ( 8, 14 ) ] ) 1441 | 1442 | Map number by multiplying with accumulated sum: 1443 | 1444 | mapAccuml (\a x -> ( a + x, a * x )) 5 [ 2, 4, 8 ] 1445 | --> ( 19, [ 10, 28, 88 ] ) 1446 | 1447 | -} 1448 | mapAccuml : (a -> b -> ( a, c )) -> a -> List b -> ( a, List c ) 1449 | mapAccuml f acc0 list = 1450 | let 1451 | ( accFinal, generatedList ) = 1452 | List.foldl 1453 | (\x ( acc1, ys ) -> 1454 | let 1455 | ( acc2, y ) = 1456 | f acc1 x 1457 | in 1458 | ( acc2, y :: ys ) 1459 | ) 1460 | ( acc0, [] ) 1461 | list 1462 | in 1463 | ( accFinal, List.reverse generatedList ) 1464 | 1465 | 1466 | {-| The mapAccumr function behaves like a combination of map and foldr; it applies a 1467 | function to each element of a list, passing an accumulating parameter from right to left, 1468 | and returning a final value of this accumulator together with the new list. 1469 | 1470 | mapAccumr f a0 [ x1, x2, x3 ] == ( a3, [ y1, y2, y3 ] ) 1471 | 1472 | -- x1 x2 x3 1473 | -- | | | 1474 | -- a3 <- f --- f --- f -- a0 1475 | -- | | | 1476 | -- y1 y2 y3 1477 | 1478 | Add a count of remaining elements: 1479 | 1480 | mapAccumr (\a x -> ( a + 1, ( x, a ) )) 0 [ 2, 4, 8 ] 1481 | --> ( 3, [ ( 2, 2 ), ( 4, 1 ), ( 8, 0 ) ] ) 1482 | 1483 | Map number by multiplying with right-to-left accumulated sum: 1484 | 1485 | mapAccumr (\a x -> ( a + x, a * x )) 5 [ 2, 4, 8 ] 1486 | --> ( 19, [ 34, 52, 40 ] ) 1487 | 1488 | -} 1489 | mapAccumr : (a -> b -> ( a, c )) -> a -> List b -> ( a, List c ) 1490 | mapAccumr f acc0 list = 1491 | List.foldr 1492 | (\x ( acc1, ys ) -> 1493 | let 1494 | ( acc2, y ) = 1495 | f acc1 x 1496 | in 1497 | ( acc2, y :: ys ) 1498 | ) 1499 | ( acc0, [] ) 1500 | list 1501 | 1502 | 1503 | {-| 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. 1504 | 1505 | subtractOneUntilZero : Int -> Maybe (Int, Int) 1506 | subtractOneUntilZero i = 1507 | if i /= 0 then 1508 | Just (i, i - 1) 1509 | else 1510 | Nothing 1511 | 1512 | unfoldr subtractOneUntilZero 5 1513 | --> [ 5, 4, 3, 2, 1 ] 1514 | 1515 | -} 1516 | unfoldr : (b -> Maybe ( a, b )) -> b -> List a 1517 | unfoldr f seed = 1518 | case f seed of 1519 | Nothing -> 1520 | [] 1521 | 1522 | Just ( a, b ) -> 1523 | a :: unfoldr f b 1524 | 1525 | 1526 | {-| 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)`. 1527 | 1528 | splitAt 3 [ 1, 2, 3, 4, 5 ] 1529 | --> ( [ 1, 2, 3 ], [ 4, 5 ] ) 1530 | 1531 | splitAt 1 [ 1, 2, 3 ] 1532 | --> ( [ 1 ], [ 2, 3 ] ) 1533 | 1534 | splitAt 3 [ 1, 2, 3 ] 1535 | --> ( [ 1, 2, 3 ], [] ) 1536 | 1537 | splitAt 4 [ 1, 2, 3 ] 1538 | --> ( [ 1, 2, 3 ], [] ) 1539 | 1540 | splitAt 0 [ 1, 2, 3 ] 1541 | --> ( [], [ 1, 2, 3 ] ) 1542 | 1543 | splitAt -1 [ 1, 2, 3 ] 1544 | --> ( [], [ 1, 2, 3 ] ) 1545 | 1546 | -} 1547 | splitAt : Int -> List a -> ( List a, List a ) 1548 | splitAt n xs = 1549 | ( take n xs, drop n xs ) 1550 | 1551 | 1552 | {-| 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. 1553 | 1554 | splitWhen (\n -> n == 3) [ 1, 2, 3, 4, 5 ] 1555 | --> Just ( [ 1, 2 ], [ 3, 4, 5 ] ) 1556 | 1557 | splitWhen (\n -> n == 6) [ 1, 2, 3, 4, 5 ] 1558 | --> Nothing 1559 | 1560 | -} 1561 | splitWhen : (a -> Bool) -> List a -> Maybe ( List a, List a ) 1562 | splitWhen predicate list = 1563 | findIndex predicate list 1564 | |> Maybe.map (\i -> splitAt i list) 1565 | 1566 | 1567 | {-| Take elements from the right, while predicate still holds. 1568 | 1569 | takeWhileRight ((<) 5) (List.range 1 10) 1570 | --> [ 6, 7, 8, 9, 10 ] 1571 | 1572 | -} 1573 | takeWhileRight : (a -> Bool) -> List a -> List a 1574 | takeWhileRight p = 1575 | let 1576 | step x ( xs, free ) = 1577 | if p x && free then 1578 | ( x :: xs, True ) 1579 | 1580 | else 1581 | ( xs, False ) 1582 | in 1583 | first << foldr step ( [], True ) 1584 | 1585 | 1586 | {-| Drop elements from the right, while predicate still holds. 1587 | 1588 | dropWhileRight ((<) 5) (List.range 1 10) 1589 | --> [ 1, 2, 3, 4, 5 ] 1590 | 1591 | -} 1592 | dropWhileRight : (a -> Bool) -> List a -> List a 1593 | dropWhileRight p = 1594 | foldr 1595 | (\x xs -> 1596 | if p x && isEmpty xs then 1597 | [] 1598 | 1599 | else 1600 | x :: xs 1601 | ) 1602 | [] 1603 | 1604 | 1605 | {-| 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)`. 1606 | 1607 | span ((>) 3) [ 1, 2, 3, 4, 1, 2, 3, 4 ] 1608 | --> ( [ 1, 2 ], [ 3, 4, 1, 2, 3, 4 ] ) 1609 | 1610 | span ((>) 5) [ 1, 2, 3 ] 1611 | --> ( [ 1, 2, 3 ], [] ) 1612 | 1613 | span ((>) 0) [ 1, 2, 3 ] 1614 | --> ( [], [ 1, 2, 3 ] ) 1615 | 1616 | -} 1617 | span : (a -> Bool) -> List a -> ( List a, List a ) 1618 | span p xs = 1619 | ( takeWhile p xs, dropWhile p xs ) 1620 | 1621 | 1622 | {-| 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)`. 1623 | 1624 | break ((<) 3) [ 1, 2, 3, 4, 1, 2, 3, 4 ] 1625 | --> ( [ 1, 2, 3 ], [ 4, 1, 2, 3, 4 ] ) 1626 | 1627 | break ((>) 5) [ 1, 2, 3 ] 1628 | --> ( [], [ 1, 2, 3 ] ) 1629 | 1630 | break ((<) 5) [ 1, 2, 3 ] 1631 | --> ( [ 1, 2, 3 ], [] ) 1632 | 1633 | -} 1634 | break : (a -> Bool) -> List a -> ( List a, List a ) 1635 | break p = 1636 | span (not << p) 1637 | 1638 | 1639 | {-| Drop the given prefix from the list. If the list doesn't start with that prefix, return `Nothing`. 1640 | 1641 | stripPrefix [ 1, 2 ] [ 1, 2, 3, 4 ] 1642 | --> Just [ 3, 4 ] 1643 | 1644 | stripPrefix [ 1, 2, 3 ] [ 1, 2, 3, 4, 5 ] 1645 | --> Just [ 4, 5 ] 1646 | 1647 | stripPrefix [ 1, 2, 3 ] [ 1, 2, 3 ] 1648 | --> Just [] 1649 | 1650 | stripPrefix [ 1, 2, 3 ] [ 1, 2 ] 1651 | --> Nothing 1652 | 1653 | stripPrefix [ 3, 2, 1 ] [ 1, 2, 3, 4, 5 ] 1654 | --> Nothing 1655 | 1656 | -} 1657 | stripPrefix : List a -> List a -> Maybe (List a) 1658 | stripPrefix prefix xs = 1659 | let 1660 | step e m = 1661 | case m of 1662 | Nothing -> 1663 | Nothing 1664 | 1665 | Just [] -> 1666 | Nothing 1667 | 1668 | Just (x :: xs_) -> 1669 | if e == x then 1670 | Just xs_ 1671 | 1672 | else 1673 | Nothing 1674 | in 1675 | foldl step (Just xs) prefix 1676 | 1677 | 1678 | {-| Group similar elements together. `group` is equivalent to `groupWhile (==)`. 1679 | 1680 | group [ 1, 2, 2, 3, 3, 3, 2, 2, 1 ] 1681 | --> [ (1, []), (2, [ 2 ]), (3, [ 3, 3 ]), (2, [ 2 ]), ( 1, []) ] 1682 | 1683 | -} 1684 | group : List a -> List ( a, List a ) 1685 | group = 1686 | groupWhile (==) 1687 | 1688 | 1689 | {-| 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. 1690 | 1691 | `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. 1692 | 1693 | groupWhile 1694 | (==) 1695 | [ 1, 2, 3 ] 1696 | --> [ ( 1, [] ), ( 2, [] ), ( 3, [] ) ] 1697 | 1698 | groupWhile 1699 | (<) 1700 | [ 1, 2, 3, 2, 4, 1, 3, 2, 1 ] 1701 | --> [ ( 1, [ 2, 3 ] ), ( 2, [ 4 ] ), ( 1, [ 3 ] ), ( 2, [] ), ( 1, [] ) ] 1702 | 1703 | groupWhile 1704 | (\a b -> a.id == b.id) 1705 | [ { value = 4, id = 9 }, { value = 7, id = 2 }, { value = 1, id = 2 } ] 1706 | --> [ ( { value = 4, id = 9 }, [] ), ( { value = 7, id = 2 }, [ { value = 1, id = 2 } ] ) ] 1707 | 1708 | **Note:** 1709 | The 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. 1710 | 1711 | -} 1712 | groupWhile : (a -> a -> Bool) -> List a -> List ( a, List a ) 1713 | groupWhile isSameGroup items = 1714 | List.foldr 1715 | (\x acc -> 1716 | case acc of 1717 | [] -> 1718 | [ ( x, [] ) ] 1719 | 1720 | ( y, restOfGroup ) :: groups -> 1721 | if isSameGroup x y then 1722 | ( x, y :: restOfGroup ) :: groups 1723 | 1724 | else 1725 | ( x, [] ) :: acc 1726 | ) 1727 | [] 1728 | items 1729 | 1730 | 1731 | {-| Return all initial segments of a list, from shortest to longest, empty list first, the list itself last. 1732 | 1733 | inits [ 1, 2, 3 ] 1734 | --> [ [], [ 1 ], [ 1, 2 ], [ 1, 2, 3 ] ] 1735 | 1736 | -} 1737 | inits : List a -> List (List a) 1738 | inits = 1739 | foldr (\e acc -> [] :: map ((::) e) acc) [ [] ] 1740 | 1741 | 1742 | {-| Return all final segments of a list, from longest to shortest, the list itself first, empty list last. 1743 | 1744 | tails [ 1, 2, 3 ] 1745 | --> [ [ 1, 2, 3 ], [ 2, 3 ], [ 3 ], [] ] 1746 | 1747 | -} 1748 | tails : List a -> List (List a) 1749 | tails = 1750 | foldr tailsHelp [ [] ] 1751 | 1752 | 1753 | tailsHelp : a -> List (List a) -> List (List a) 1754 | tailsHelp e list = 1755 | case list of 1756 | x :: xs -> 1757 | (e :: x) :: x :: xs 1758 | 1759 | [] -> 1760 | [] 1761 | 1762 | 1763 | {-| 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. 1764 | 1765 | select [ 1, 2, 3, 4 ] 1766 | --> [ ( 1, [ 2, 3, 4 ] ), ( 2, [ 1, 3, 4 ] ), ( 3, [ 1, 2, 4 ] ), ( 4, [ 1, 2, 3 ] ) ] 1767 | 1768 | -} 1769 | select : List a -> List ( a, List a ) 1770 | select list = 1771 | case list of 1772 | [] -> 1773 | [] 1774 | 1775 | x :: xs -> 1776 | ( x, xs ) :: map (\( y, ys ) -> ( y, x :: ys )) (select xs) 1777 | 1778 | 1779 | {-| Return all combinations in the form of (elements before, element, elements after). 1780 | 1781 | selectSplit [ 1, 2, 3 ] 1782 | --> [ ( [], 1, [ 2, 3 ] ), ( [ 1 ], 2, [ 3 ] ), ( [ 1, 2 ], 3, [] ) ] 1783 | 1784 | -} 1785 | selectSplit : List a -> List ( List a, a, List a ) 1786 | selectSplit list = 1787 | case list of 1788 | [] -> 1789 | [] 1790 | 1791 | x :: xs -> 1792 | ( [], x, xs ) :: map (\( lys, y, rys ) -> ( x :: lys, y, rys )) (selectSplit xs) 1793 | 1794 | 1795 | {-| Take two lists and return `True`, if the first list is the prefix of the second list. 1796 | -} 1797 | isPrefixOf : List a -> List a -> Bool 1798 | isPrefixOf prefix list = 1799 | case ( prefix, list ) of 1800 | ( [], _ ) -> 1801 | True 1802 | 1803 | ( _ :: _, [] ) -> 1804 | False 1805 | 1806 | ( p :: ps, x :: xs ) -> 1807 | if p == x then 1808 | isPrefixOf ps xs 1809 | 1810 | else 1811 | False 1812 | 1813 | 1814 | {-| Take two lists and return `True`, if the first list is the suffix of the second list. 1815 | -} 1816 | isSuffixOf : List a -> List a -> Bool 1817 | isSuffixOf suffix xs = 1818 | isPrefixOf (reverse suffix) (reverse xs) 1819 | 1820 | 1821 | {-| Return True if all the elements of the first list occur in-order and 1822 | consecutively anywhere within the second. 1823 | 1824 | isInfixOf [ 5, 7, 11 ] [ 2, 3, 5, 7, 11, 13 ] 1825 | --> True 1826 | 1827 | isInfixOf [ 5, 7, 13 ] [ 2, 3, 5, 7, 11, 13 ] 1828 | --> False 1829 | 1830 | isInfixOf [ 3, 5, 2 ] [ 2, 3, 5, 7, 11, 13 ] 1831 | --> False 1832 | 1833 | -} 1834 | isInfixOf : List a -> List a -> Bool 1835 | isInfixOf infixList list = 1836 | case infixList of 1837 | [] -> 1838 | True 1839 | 1840 | x :: xs -> 1841 | isInfixOfHelp x xs list 1842 | 1843 | 1844 | isInfixOfHelp : a -> List a -> List a -> Bool 1845 | isInfixOfHelp infixHead infixTail list = 1846 | case list of 1847 | [] -> 1848 | False 1849 | 1850 | x :: xs -> 1851 | if x == infixHead && isPrefixOf infixTail xs then 1852 | True 1853 | 1854 | else 1855 | isInfixOfHelp infixHead infixTail xs 1856 | 1857 | 1858 | {-| Return True if all the elements of the first list occur, in order, in the 1859 | second. The elements do not have to occur consecutively. 1860 | 1861 | isSubsequenceOf 1862 | [ "E", "l", "m" ] 1863 | [ "E", "a", "t", " ", "l", "i", "m", "e", "s" ] 1864 | --> True 1865 | 1866 | isSubsequenceOf 1867 | [ "E", "l", "m" ] 1868 | [ "E", "m", "a", "i", "l" ] 1869 | --> False 1870 | 1871 | -} 1872 | isSubsequenceOf : List a -> List a -> Bool 1873 | isSubsequenceOf subseq list = 1874 | case ( subseq, list ) of 1875 | ( [], _ ) -> 1876 | True 1877 | 1878 | ( _, [] ) -> 1879 | False 1880 | 1881 | ( x :: xs, y :: ys ) -> 1882 | if x == y then 1883 | isSubsequenceOf xs ys 1884 | 1885 | else 1886 | isSubsequenceOf subseq ys 1887 | 1888 | 1889 | {-| Take two lists and return `True`, if the first list is a permutation of the second list. 1890 | In other words: Do the 2 `List`s contain the same elements but in a different order? 1891 | 1892 | [ 3, 1, 2 ] 1893 | |> isPermutationOf 1894 | [ 1, 2, 3 ] 1895 | --> True 1896 | 1897 | [ 3, 1, 0 ] 1898 | |> isPermutationOf 1899 | [ 1, 2, 3 ] 1900 | --> False 1901 | 1902 | [ 3, 1, 2, 2 ] 1903 | |> isPermutationOf 1904 | [ 1, 2, 3 ] 1905 | --> False 1906 | 1907 | -} 1908 | isPermutationOf : List a -> List a -> Bool 1909 | isPermutationOf permut xs = 1910 | case xs of 1911 | [] -> 1912 | List.isEmpty permut 1913 | 1914 | x :: after -> 1915 | let 1916 | { foundAny, without } = 1917 | removeOneMember x permut 1918 | in 1919 | if foundAny then 1920 | isPermutationOf without after 1921 | 1922 | else 1923 | False 1924 | 1925 | 1926 | removeOneMember : a -> List a -> { foundAny : Bool, without : List a } 1927 | removeOneMember culprit l = 1928 | removeOneMemberHelp culprit [] l 1929 | 1930 | 1931 | removeOneMemberHelp culprit before list = 1932 | case list of 1933 | [] -> 1934 | { foundAny = False, without = [] } 1935 | 1936 | head :: after -> 1937 | if head == culprit then 1938 | { foundAny = True, without = before ++ after } 1939 | 1940 | else 1941 | removeOneMemberHelp culprit (head :: before) after 1942 | 1943 | 1944 | {-| Take two lists and returns a list of corresponding pairs 1945 | -} 1946 | zip : List a -> List b -> List ( a, b ) 1947 | zip = 1948 | map2 Tuple.pair 1949 | 1950 | 1951 | {-| Take three lists and returns a list of triples 1952 | -} 1953 | zip3 : List a -> List b -> List c -> List ( a, b, c ) 1954 | zip3 = 1955 | map3 triple 1956 | 1957 | 1958 | triple : a -> b -> c -> ( a, b, c ) 1959 | triple a b c = 1960 | ( a, b, c ) 1961 | 1962 | 1963 | {-| Map functions taking multiple arguments over multiple lists, regardless of list length. 1964 | All possible combinations will be explored. 1965 | 1966 | lift2 (+) [1,2,3][4,5] 1967 | --> [5,6,6,7,7,8] 1968 | 1969 | -} 1970 | lift2 : (a -> b -> c) -> List a -> List b -> List c 1971 | lift2 f la lb = 1972 | la |> andThen (\a -> lb |> andThen (\b -> [ f a b ])) 1973 | 1974 | 1975 | {-| -} 1976 | lift3 : (a -> b -> c -> d) -> List a -> List b -> List c -> List d 1977 | lift3 f la lb lc = 1978 | la |> andThen (\a -> lb |> andThen (\b -> lc |> andThen (\c -> [ f a b c ]))) 1979 | 1980 | 1981 | {-| -} 1982 | lift4 : (a -> b -> c -> d -> e) -> List a -> List b -> List c -> List d -> List e 1983 | lift4 f la lb lc ld = 1984 | la |> andThen (\a -> lb |> andThen (\b -> lc |> andThen (\c -> ld |> andThen (\d -> [ f a b c d ])))) 1985 | 1986 | 1987 | {-| Split list into groups of length `size`. If there are not enough elements 1988 | to completely fill the last group, it will not be included. This is equivalent 1989 | to calling `groupsOfWithStep` with the same `size` and `step`. 1990 | 1991 | groupsOf 3 (List.range 1 10) 1992 | --> [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ] 1993 | 1994 | -} 1995 | groupsOf : Int -> List a -> List (List a) 1996 | groupsOf size xs = 1997 | groupsOfWithStep size size xs 1998 | 1999 | 2000 | {-| Split list into groups of length `size` at offsets `step` apart. If there 2001 | are not enough elements to completely fill the last group, it will not be 2002 | included. (See `greedyGroupsOfWithStep` if you would like the last group to be 2003 | included regardless.) 2004 | 2005 | groupsOfWithStep 4 4 (List.range 1 10) 2006 | --> [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ] ] 2007 | 2008 | groupsOfWithStep 3 1 (List.range 1 5) 2009 | --> [ [ 1, 2, 3 ], [ 2, 3, 4 ], [ 3, 4, 5 ] ] 2010 | 2011 | groupsOfWithStep 3 6 (List.range 1 20) 2012 | --> [ [ 1, 2, 3 ], [ 7, 8, 9 ], [ 13, 14, 15 ] ] 2013 | 2014 | If `step == size`, every element (except for perhaps the last few due to the 2015 | non-greedy behavior) will appear in exactly one group. If `step < size`, there 2016 | will be an overlap between groups. If `step > size`, some elements will be 2017 | skipped and not appear in any groups. 2018 | 2019 | -} 2020 | groupsOfWithStep : Int -> Int -> List a -> List (List a) 2021 | groupsOfWithStep size step list = 2022 | if size <= 0 || step <= 0 then 2023 | [] 2024 | 2025 | else 2026 | let 2027 | go : List a -> List (List a) -> List (List a) 2028 | go xs acc = 2029 | if List.isEmpty xs then 2030 | List.reverse acc 2031 | 2032 | else 2033 | let 2034 | thisGroup = 2035 | List.take size xs 2036 | in 2037 | if size == List.length thisGroup then 2038 | let 2039 | rest = 2040 | List.drop step xs 2041 | in 2042 | go rest (thisGroup :: acc) 2043 | 2044 | else 2045 | List.reverse acc 2046 | in 2047 | go list [] 2048 | 2049 | 2050 | {-| `groupsOfVarying ns` takes `n` elements from a list for each `n` in `ns`, splitting the list into variably sized segments 2051 | 2052 | groupsOfVarying [ 2, 3, 1 ] [ "a", "b", "c", "d", "e", "f" ] 2053 | --> [ [ "a", "b" ], [ "c", "d", "e" ], [ "f" ] ] 2054 | 2055 | groupsOfVarying [ 2 ] [ "a", "b", "c", "d", "e", "f" ] 2056 | --> [ [ "a", "b" ] ] 2057 | 2058 | groupsOfVarying [ 2, 3, 1, 5, 6 ] [ "a", "b", "c", "d", "e" ] 2059 | --> [ [ "a", "b" ], [ "c", "d", "e" ] ] 2060 | 2061 | -} 2062 | groupsOfVarying : List Int -> List a -> List (List a) 2063 | groupsOfVarying listOfLengths list = 2064 | groupsOfVarying_ listOfLengths list [] 2065 | 2066 | 2067 | groupsOfVarying_ : List Int -> List a -> List (List a) -> List (List a) 2068 | groupsOfVarying_ listOfLengths list accu = 2069 | case ( listOfLengths, list ) of 2070 | ( length :: tailLengths, _ :: _ ) -> 2071 | let 2072 | ( head, tail ) = 2073 | splitAt length list 2074 | in 2075 | groupsOfVarying_ tailLengths tail (head :: accu) 2076 | 2077 | _ -> 2078 | List.reverse accu 2079 | 2080 | 2081 | {-| Greedily split list into groups of length `size`. The last group of 2082 | elements will be included regardless of whether there are enough elements in 2083 | the list to completely fill it. This is equivalent to calling 2084 | `greedyGroupsOfWithStep` with the same `size` and `step`. 2085 | 2086 | greedyGroupsOf 3 (List.range 1 10) 2087 | --> [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ], [ 10 ] ] 2088 | 2089 | -} 2090 | greedyGroupsOf : Int -> List a -> List (List a) 2091 | greedyGroupsOf size xs = 2092 | greedyGroupsOfWithStep size size xs 2093 | 2094 | 2095 | {-| Greedily split list into groups of length `size` at offsets `step` apart. 2096 | The last group of elements will be included regardless of whether there are 2097 | enough elements in the list to completely fill it. (See `groupsOfWithStep` 2098 | for the non-greedy version of this function). 2099 | 2100 | greedyGroupsOfWithStep 4 4 (List.range 1 10) 2101 | --> [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9, 10 ] ] 2102 | 2103 | greedyGroupsOfWithStep 3 2 (List.range 1 6) 2104 | --> [ [ 1, 2, 3 ], [ 3, 4, 5 ], [ 5, 6 ] ] 2105 | 2106 | greedyGroupsOfWithStep 3 6 (List.range 1 20) 2107 | --> [ [ 1, 2, 3 ], [ 7, 8, 9 ], [ 13, 14, 15 ], [ 19, 20 ] ] 2108 | 2109 | If `step == size`, every element will appear in exactly one group. If 2110 | `step < size`, there will be an overlap between groups. If `step > size`, some 2111 | elements will be skipped and not appear in any groups. 2112 | 2113 | -} 2114 | greedyGroupsOfWithStep : Int -> Int -> List a -> List (List a) 2115 | greedyGroupsOfWithStep size step list = 2116 | if size <= 0 || step <= 0 then 2117 | [] 2118 | 2119 | else 2120 | let 2121 | go : List a -> List (List a) -> List (List a) 2122 | go xs acc = 2123 | if List.isEmpty xs then 2124 | List.reverse acc 2125 | 2126 | else 2127 | go 2128 | (List.drop step xs) 2129 | (List.take size xs :: acc) 2130 | in 2131 | go list [] 2132 | 2133 | 2134 | {-| Group equal elements together. This is different from `group` as each sublist 2135 | will contain _all_ equal elements of the original list. Elements will be grouped 2136 | in the same order as they appear in the original list. The same applies to elements 2137 | within each group. 2138 | 2139 | gatherEquals [1,2,1,3,2] 2140 | --> [(1,[1]),(2,[2]),(3,[])] 2141 | 2142 | -} 2143 | gatherEquals : List a -> List ( a, List a ) 2144 | gatherEquals list = 2145 | gatherWith (==) list 2146 | 2147 | 2148 | {-| Group equal elements together. A function is applied to each element of the list 2149 | and then the equality check is performed against the results of that function evaluation. 2150 | Elements will be grouped in the same order as they appear in the original list. The 2151 | same applies to elements within each group. 2152 | 2153 | gatherEqualsBy .age [{age=25},{age=23},{age=25}] 2154 | --> [({age=25},[{age=25}]),({age=23},[])] 2155 | 2156 | -} 2157 | gatherEqualsBy : (a -> b) -> List a -> List ( a, List a ) 2158 | gatherEqualsBy extract list = 2159 | gatherWith (\a b -> extract a == extract b) list 2160 | 2161 | 2162 | {-| Group equal elements together using a custom equality function. Elements will be 2163 | grouped in the same order as they appear in the original list. The same applies to 2164 | elements within each group. 2165 | 2166 | gatherWith (==) [1,2,1,3,2] 2167 | --> [(1,[1]),(2,[2]),(3,[])] 2168 | 2169 | -} 2170 | gatherWith : (a -> a -> Bool) -> List a -> List ( a, List a ) 2171 | gatherWith testFn list = 2172 | let 2173 | helper : List a -> List ( a, List a ) -> List ( a, List a ) 2174 | helper scattered gathered = 2175 | case scattered of 2176 | [] -> 2177 | List.reverse gathered 2178 | 2179 | toGather :: population -> 2180 | let 2181 | ( gathering, remaining ) = 2182 | List.partition (testFn toGather) population 2183 | in 2184 | helper remaining (( toGather, gathering ) :: gathered) 2185 | in 2186 | helper list [] 2187 | 2188 | 2189 | {-| Calculate the number of occurences for each element in a list. Elements 2190 | will be ordered ascendingly, then grouped in a tuple with the number of 2191 | occurences. 2192 | 2193 | frequencies [2,1,3,2,3,3] 2194 | --> [(1,1),(2,2),(3,3)] 2195 | 2196 | -} 2197 | frequencies : List comparable -> List ( comparable, Int ) 2198 | frequencies list = 2199 | list 2200 | |> List.sort 2201 | |> group 2202 | |> List.map (\( x, y ) -> ( x, 1 + List.length y )) 2203 | 2204 | 2205 | {-| Performs an inner join, combining data items from both lists if they match by their respective key functions. 2206 | 2207 | employees : List { name : String, departmentId : Int } 2208 | employees = 2209 | [ { name = "Rafferty", departmentId = 31 } 2210 | , { name = "Jones", departmentId = 33 } 2211 | , { name = "Heisenberg", departmentId = 33 } 2212 | , { name = "Robinson", departmentId = 34 } 2213 | , { name = "Smith", departmentId = 34 } 2214 | ] 2215 | 2216 | departments : List { name : String, departmentId : Int } 2217 | departments = 2218 | [ { departmentId = 31, name = "Sales" } 2219 | , { departmentId = 33, name = "Engineering" } 2220 | , { departmentId = 34, name = "Clerical" } 2221 | , { departmentId = 35, name = "Marketing" } 2222 | ] 2223 | 2224 | joinOn (\empl dep -> { employee = empl.name, department = dep.name}) .departmentId .departmentId employees departments 2225 | --> [ { department = "Clerical", employee = "Robinson" } 2226 | --> , { department = "Clerical", employee = "Smith" } 2227 | --> , { department = "Engineering", employee = "Jones" } 2228 | --> , { department = "Engineering", employee = "Heisenberg" } 2229 | --> , { department = "Sales", employee = "Rafferty" } 2230 | --> ] 2231 | 2232 | This is akin to the SQL query: 2233 | 2234 | SELECT employee.name, department.name 2235 | FROM employee 2236 | INNER JOIN department 2237 | ON employee.departmentId = department.departmentId 2238 | 2239 | -} 2240 | joinOn : (a -> b -> c) -> (a -> comparable) -> (b -> comparable) -> List a -> List b -> List c 2241 | joinOn selectFn aKeyFn bKeyFn aList bList = 2242 | let 2243 | aListWithKeys : List ( ( comparable, a ), List ( comparable, a ) ) 2244 | aListWithKeys = 2245 | List.map (\a -> ( aKeyFn a, a )) aList 2246 | |> List.sortBy Tuple.first 2247 | |> gatherEqualsBy Tuple.first 2248 | 2249 | bListWithKeys : List ( ( comparable, b ), List ( comparable, b ) ) 2250 | bListWithKeys = 2251 | List.map (\b -> ( bKeyFn b, b )) bList 2252 | |> List.sortBy Tuple.first 2253 | |> gatherEqualsBy Tuple.first 2254 | 2255 | helper : List ( ( comparable, a ), List ( comparable, a ) ) -> List ( ( comparable, b ), List ( comparable, b ) ) -> List c -> List c 2256 | helper aInp bInp result = 2257 | case ( aInp, bInp ) of 2258 | ( ( ( aKey, a ), ass ) :: restAs, ( ( bKey, b ), bss ) :: restBs ) -> 2259 | if aKey == bKey then 2260 | let 2261 | prod = 2262 | List.concatMap 2263 | (\( _, sA ) -> 2264 | List.map 2265 | (\( _, sB ) -> 2266 | selectFn sA sB 2267 | ) 2268 | (( bKey, b ) :: bss) 2269 | ) 2270 | (( aKey, a ) :: ass) 2271 | in 2272 | helper restAs restBs (prod ++ result) 2273 | 2274 | else if aKey < bKey then 2275 | helper restAs bInp result 2276 | 2277 | else 2278 | helper aInp restBs result 2279 | 2280 | _ -> 2281 | result 2282 | in 2283 | helper aListWithKeys bListWithKeys [] 2284 | --------------------------------------------------------------------------------