├── .gitignore ├── LICENSE ├── README.md ├── elm-package.json └── src └── List └── Extra.elm /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore build or dist files 2 | /elm-stuff 3 | -------------------------------------------------------------------------------- /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 | DEPRECATED: Renamed to http://package.elm-lang.org/packages/elm-community/list-extra 3 | 4 | Experimental package with convenience functions for working with List. 5 | Note that this API is experimental and likely to go through many more iterations. 6 | 7 | Feedback and contributions are very welcome. 8 | 9 | 10 | -------------------------------------------------------------------------------- /elm-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "summary": "DEPRECATED: Use http://package.elm-lang.org/packages/elm-community/list-extra", 4 | "repository": "https://github.com/elm-community/elm-list-extra.git", 5 | "license": "MIT", 6 | "source-directories": [ 7 | "src" 8 | ], 9 | "exposed-modules": [ 10 | "List.Extra" 11 | ], 12 | "dependencies": { 13 | "elm-lang/core": "4.0.0 <= v <= 4.0.0" 14 | }, 15 | "elm-version": "0.17.0 <= v < 0.18.0" 16 | } -------------------------------------------------------------------------------- /src/List/Extra.elm: -------------------------------------------------------------------------------- 1 | module List.Extra exposing ( last 2 | , init 3 | , getAt, (!!) 4 | , uncons 5 | , minimumBy 6 | , maximumBy 7 | , andMap, andThen 8 | , takeWhile 9 | , dropWhile 10 | , dropDuplicates 11 | , replaceIf 12 | , setAt 13 | , deleteIf 14 | , updateIf 15 | , updateAt 16 | , updateIfIndex 17 | , singleton 18 | , removeAt 19 | , removeWhen 20 | , iterate 21 | , intercalate, transpose, subsequences, permutations, interweave 22 | , foldl1, foldr1 23 | , scanl1, scanr, scanr1, unfoldr 24 | , splitAt, takeWhileEnd, dropWhileEnd, span, break, stripPrefix 25 | , group, groupWhile, groupWhileTransitively, inits, tails, select, selectSplit 26 | , isPrefixOf, isSuffixOf, isInfixOf, isSubsequenceOf, isPermutationOf 27 | , notMember, find 28 | , elemIndex, elemIndices, findIndex, findIndices 29 | , zip 30 | , zip3 31 | , zip4 32 | , zip5 33 | , lift2 34 | , lift3 35 | , lift4 36 | , groupsOf, groupsOfWithStep, greedyGroupsOf, greedyGroupsOfWithStep 37 | ) 38 | {-| Convenience functions for working with List 39 | 40 | # Basics 41 | @docs last, init, getAt, (!!), uncons, maximumBy, minimumBy, andMap, andThen, takeWhile, dropWhile, dropDuplicates, replaceIf, setAt, deleteIf, updateIf, updateAt, updateIfIndex, singleton, removeAt, removeWhen 42 | 43 | # List transformations 44 | @docs intercalate, transpose, subsequences, permutations, interweave 45 | 46 | # Folds 47 | @docs foldl1, foldr1 48 | 49 | # Building lists 50 | @docs scanl1, scanr, scanr1, unfoldr, iterate 51 | 52 | # Sublists 53 | @docs splitAt, takeWhileEnd, dropWhileEnd, span, break, stripPrefix, group, groupWhile, groupWhileTransitively, inits, tails, select, selectSplit 54 | 55 | # Predicates 56 | @docs isPrefixOf, isSuffixOf, isInfixOf, isSubsequenceOf, isPermutationOf 57 | 58 | # Searching 59 | @docs notMember, find, elemIndex, elemIndices, findIndex, findIndices 60 | 61 | # Zipping 62 | @docs zip, zip3, zip4, zip5 63 | 64 | # Lift functions onto multiple lists of arguments 65 | @docs lift2, lift3, lift4 66 | 67 | # Split to groups of given size 68 | @docs groupsOf, groupsOfWithStep, greedyGroupsOf, greedyGroupsOfWithStep 69 | -} 70 | 71 | import List exposing (..) 72 | import Set exposing (Set) 73 | 74 | 75 | {-| Extract the last element of a list. 76 | 77 | last [1,2,3] == Just 3 78 | last [] == Nothing 79 | -} 80 | last : List a -> Maybe a 81 | last = foldl1 (flip always) 82 | 83 | {-| Return all elements of the list except the last one. 84 | 85 | init [1,2,3] == Just [1,2] 86 | init [] == Nothing 87 | -} 88 | init : List a -> Maybe (List a) 89 | init = 90 | let 91 | maybe : b -> (a -> b) -> Maybe a -> b 92 | maybe d f = Maybe.withDefault d << Maybe.map f 93 | in 94 | foldr ((<<) Just << maybe [] << (::)) Nothing 95 | 96 | {-| Returns `Just` the element at the given index in the list, 97 | or `Nothing` if the index is out of range. 98 | -} 99 | getAt : Int -> List a -> Maybe a 100 | getAt idx xs = 101 | if idx < 0 then 102 | Nothing 103 | else 104 | List.head <| List.drop idx xs 105 | 106 | {-| Alias for getAt, but with the parameters flipped. 107 | -} 108 | (!!) : List a -> Int -> Maybe a 109 | (!!) = flip getAt 110 | 111 | {-| Returns a list of repeated applications of `f`. 112 | 113 | If `f` returns `Nothing` the iteration will stop. If it returns `Just y` then `y` will be added to the list and the iteration will continue with `f y`. 114 | nextYear : Int -> Maybe Int 115 | nextYear year = 116 | if year >= 2030 then 117 | Nothing 118 | else 119 | Just (year + 1) 120 | -- Will evaluate to [2010, 2011, ..., 2030] 121 | iterate nextYear 2010 122 | -} 123 | iterate : (a -> Maybe a) -> a -> List a 124 | iterate f x = 125 | case f x of 126 | Just x' -> x :: iterate f x' 127 | Nothing -> [x] 128 | 129 | 130 | {-| 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. 131 | 132 | uncons [1,2,3] == Just (1, [2,3]) 133 | uncons [] = Nothing 134 | -} 135 | uncons : List a -> Maybe (a, List a) 136 | uncons xs = 137 | case xs of 138 | [] -> Nothing 139 | (x::xs) -> Just (x,xs) 140 | 141 | {-| Find the first maximum element in a list using a comparable transformation 142 | -} 143 | maximumBy : (a -> comparable) -> List a -> Maybe a 144 | maximumBy f ls = 145 | let maxBy x (y, fy) = let fx = f x in if fx > fy then (x, fx) else (y, fy) 146 | in case ls of 147 | [l'] -> Just l' 148 | l'::ls' -> Just <| fst <| foldl maxBy (l', f l') ls' 149 | _ -> Nothing 150 | 151 | {-| Find the first minimum element in a list using a comparable transformation 152 | -} 153 | minimumBy : (a -> comparable) -> List a -> Maybe a 154 | minimumBy f ls = 155 | let minBy x (y, fy) = let fx = f x in if fx < fy then (x, fx) else (y, fy) 156 | in case ls of 157 | [l'] -> Just l' 158 | l'::ls' -> Just <| fst <| foldl minBy (l', f l') ls' 159 | _ -> Nothing 160 | 161 | {-| Take elements in order as long as the predicate evaluates to `True` 162 | -} 163 | takeWhile : (a -> Bool) -> List a -> List a 164 | takeWhile predicate list = 165 | case list of 166 | [] -> [] 167 | x::xs -> if (predicate x) then x :: takeWhile predicate xs 168 | else [] 169 | 170 | {-| Drop elements in order as long as the predicate evaluates to `True` 171 | -} 172 | dropWhile : (a -> Bool) -> List a -> List a 173 | dropWhile predicate list = 174 | case list of 175 | [] -> [] 176 | x::xs -> if (predicate x) then dropWhile predicate xs 177 | else list 178 | 179 | {-| Drop all duplicates 180 | -} 181 | dropDuplicates : List comparable -> List comparable 182 | dropDuplicates list = 183 | dropDuplicatesHelp Set.empty list 184 | 185 | 186 | dropDuplicatesHelp : Set comparable -> List comparable -> List comparable 187 | dropDuplicatesHelp existing remaining = 188 | case remaining of 189 | [] -> 190 | [] 191 | 192 | first :: rest -> 193 | if Set.member first existing then 194 | dropDuplicatesHelp existing rest 195 | else 196 | first :: dropDuplicatesHelp (Set.insert first existing) rest 197 | 198 | 199 | {-| Map functions taking multiple arguments over multiple lists. Each list should be of the same length. 200 | 201 | ( (\a b c -> a + b * c) 202 | `map` [1,2,3] 203 | `andMap` [4,5,6] 204 | `andMap` [2,1,1] 205 | ) == [9,7,9] 206 | -} 207 | andMap : List (a -> b) -> List a -> List b 208 | andMap fl l = map2 (<|) fl l 209 | 210 | {-| Equivalent to `concatMap` with arguments reversed. Ideal to use as an infix function, chaining together functions that return List. For example, suppose you want to have a cartesian product of [1,2] and [3,4]: 211 | 212 | [1,2] `andThen` \x -> 213 | [3,4] `andThen` \y -> 214 | [(x,y)] 215 | 216 | will give back the list: 217 | 218 | [(1,3),(1,4),(2,3),(2,4)] 219 | 220 | Now suppose we want to have a cartesian product between the first list and the second list and its doubles: 221 | 222 | [1,2] `andThen` \x -> 223 | [3,4] `andThen` \y -> 224 | [y,y*2] `andThen` \z -> 225 | [(x,z)] 226 | 227 | will give back the list: 228 | 229 | [(1,3),(1,6),(1,4),(1,8),(2,3),(2,6),(2,4),(2,8)] 230 | 231 | Advanced functional programmers will recognize this as the implementation of bind operator (>>=) for lists from the `Monad` typeclass. 232 | -} 233 | andThen : List a -> (a -> List b) -> List b 234 | andThen = flip concatMap 235 | 236 | 237 | {-| Negation of `member`. 238 | 239 | 1 `notMember` [1,2,3] == False 240 | 4 `notMember` [1,2,3] == True 241 | -} 242 | notMember : a -> List a -> Bool 243 | notMember x = not << member x 244 | 245 | {-| Find the first element that satisfies a predicate and return 246 | Just that element. If none match, return Nothing. 247 | 248 | find (\num -> num > 5) [2, 4, 6, 8] == Just 6 249 | -} 250 | find : (a -> Bool) -> List a -> Maybe a 251 | find predicate list = 252 | case list of 253 | [] -> 254 | Nothing 255 | 256 | first::rest -> 257 | if predicate first then 258 | Just first 259 | else 260 | find predicate rest 261 | 262 | {-| Return the index of the first occurrence of the element. Otherwise, return `Nothing`. Indexing starts from 0. 263 | 264 | elemIndex 1 [1,2,3] == Just 0 265 | elemIndex 4 [1,2,3] == Nothing 266 | elemIndex 1 [1,2,1] == Just 0 267 | -} 268 | elemIndex : a -> List a -> Maybe Int 269 | elemIndex x = findIndex ((==)x) 270 | 271 | {-| Return all indices of occurrences of the element. If element is not found, return empty list. Indexing starts from 0. 272 | 273 | elemIndices 1 [1,2,3] == [0] 274 | elemIndices 4 [1,2,3] == [] 275 | elemIndices 1 [1,2,1] == [0,2] 276 | -} 277 | elemIndices : a -> List a -> List Int 278 | elemIndices x = findIndices ((==)x) 279 | 280 | {-| Take a predicate and a list, return the index of the first element that satisfies the predicate. Otherwise, return `Nothing`. Indexing starts from 0. 281 | 282 | findIndex isEven [1,2,3] == Just 1 283 | findIndex isEven [1,3,5] == Nothing 284 | findIndex isEven [1,2,4] == Just 1 285 | -} 286 | findIndex : (a -> Bool) -> List a -> Maybe Int 287 | findIndex p = head << findIndices p 288 | 289 | {-| Take a predicate and a list, return indices of all elements satisfying the predicate. Otherwise, return empty list. Indexing starts from 0. 290 | 291 | findIndices isEven [1,2,3] == [1] 292 | findIndices isEven [1,3,5] == [] 293 | findIndices isEven [1,2,4] == [1,2] 294 | -} 295 | findIndices : (a -> Bool) -> List a -> List Int 296 | findIndices p = map fst << filter (\(i,x) -> p x) << indexedMap (,) 297 | 298 | {-| Replace all values that satisfy a predicate with a replacement value. 299 | -} 300 | replaceIf : (a -> Bool) -> a -> List a -> List a 301 | replaceIf predicate replacement list = 302 | updateIf predicate (always replacement) list 303 | 304 | {-| Replace all values that satisfy a predicate by calling an update function. 305 | -} 306 | updateIf : (a -> Bool) -> (a -> a) -> List a -> List a 307 | updateIf predicate update list = 308 | List.map (\item -> if predicate item then update item else item) list 309 | 310 | {-| Replace a value at a specific index by calling an update function. 311 | -} 312 | updateAt : Int -> (a -> a) -> List a -> Maybe (List a) 313 | updateAt index update list = 314 | if index < 0 || index >= List.length list then 315 | Nothing 316 | else 317 | Just <| updateIfIndex ((==) index) update list 318 | 319 | {-| Replace a value at an index that satisfies a predicate. 320 | -} 321 | updateIfIndex : (Int -> Bool) -> (a -> a) -> List a -> List a 322 | updateIfIndex predicate update list = 323 | List.indexedMap (\i x -> if predicate i then update x else x) list 324 | 325 | {-| Remove all values that satisfy a predicate 326 | -} 327 | deleteIf : (a -> Bool) -> List a -> List a 328 | deleteIf predicate items = 329 | List.filter (not << predicate) items 330 | 331 | {-| Set a value in a list by index. Returns the updated list if the index is in range, or Nothing if it is out of range. 332 | -} 333 | setAt : Int -> a -> List a -> Maybe (List a) 334 | setAt index value l = 335 | if index < 0 then 336 | Nothing 337 | else 338 | let 339 | head = List.take index l 340 | tail = List.drop index l |> List.tail 341 | in 342 | case tail of 343 | Nothing -> 344 | Nothing 345 | 346 | Just t -> 347 | Just (value :: t |> List.append head) 348 | 349 | 350 | {-| Convert a value to a list containing one value. 351 | 352 | singleton 3 == [3] 353 | -} 354 | singleton : a -> List a 355 | singleton x = [x] 356 | 357 | {-| Remove the element at an index from a list. If the index is out of range, this returns the original list unchanged. Otherwise, it returns the updated list. 358 | -} 359 | removeAt : Int -> List a -> List a 360 | removeAt index l = 361 | if index < 0 then 362 | l 363 | else 364 | let 365 | head = List.take index l 366 | tail = List.drop index l |> List.tail 367 | in 368 | case tail of 369 | Nothing -> 370 | l 371 | 372 | Just t -> 373 | List.append head t 374 | 375 | {-| Take a predicate and a list, and return a list that contains elements which fails to satisfy the predicate. 376 | This is equivalent to `List.filter (not << predicate) list`. 377 | 378 | removeWhen isEven [1,2,3,4] == [1,3] 379 | -} 380 | removeWhen : (a -> Bool) -> List a -> List a 381 | removeWhen pred list = 382 | List.filter (not << pred) list 383 | 384 | 385 | {-| 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)`. 386 | 387 | intercalate [0,0] [[1,2],[3,4],[5,6]] == [1,2,0,0,3,4,0,0,5,6] 388 | -} 389 | intercalate : List a -> List (List a) -> List a 390 | intercalate xs = concat << intersperse xs 391 | 392 | {-| Transpose rows and columns of the list of lists. 393 | 394 | transpose [[1,2,3],[4,5,6]] == [[1,4],[2,5],[3,6]] 395 | 396 | If some rows are shorter than the following rows, their elements are skipped: 397 | 398 | transpose [[10,11],[20],[],[30,31,32]] == [[10,20,30],[11,31],[32]] 399 | -} 400 | transpose : List (List a) -> List (List a) 401 | transpose ll = 402 | case ll of 403 | [] -> [] 404 | ([]::xss) -> transpose xss 405 | ((x::xs)::xss) -> 406 | let 407 | heads = filterMap head xss 408 | tails = filterMap tail xss 409 | in 410 | (x::heads)::transpose (xs::tails) 411 | 412 | {-| Return the list of all subsequences of a list. 413 | 414 | subsequences [1,2,3] == [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]] 415 | -} 416 | subsequences : List a -> List (List a) 417 | subsequences xs = []::subsequencesNonEmpty xs 418 | 419 | {-| Return the list of all subsequences of the argument, except for the empty list. 420 | 421 | subsequencesNonEmpty [1,2,3] == [[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]] 422 | -} 423 | subsequencesNonEmpty : List a -> List (List a) 424 | subsequencesNonEmpty xs = 425 | case xs of 426 | [] -> [] 427 | (x::xs) -> 428 | let f ys r = ys::(x::ys)::r 429 | in [x]::foldr f [] (subsequencesNonEmpty xs) 430 | 431 | {-| Return the list of of all permutations of a list. The result is in lexicographic order. 432 | 433 | permutations [1,2,3] == [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] 434 | -} 435 | permutations : List a -> List (List a) 436 | permutations xs' = 437 | case xs' of 438 | [] -> [[]] 439 | xs -> let f (y,ys) = map ((::)y) (permutations ys) 440 | in concatMap f (select xs) 441 | 442 | 443 | {-| Return a list that contains elements from the two provided, in alternate order. 444 | If one list runs out of items, append the items from the remaining list. 445 | 446 | interweave [1,3] [2,4] == [1,2,3,4] 447 | interweave [1,3,5,7] [2,4] == [1,2,3,4,5,7] 448 | -} 449 | interweave : List a -> List a -> List a 450 | interweave l1 l2 = 451 | interweaveHelp l1 l2 [] 452 | 453 | 454 | interweaveHelp : List a -> List a -> List a -> List a 455 | interweaveHelp l1 l2 acc = 456 | case (l1, l2) of 457 | (x::xs, y::ys) -> 458 | interweaveHelp xs ys <| acc ++ [x, y] 459 | 460 | (x, []) -> 461 | acc ++ x 462 | 463 | ([], y) -> 464 | acc ++ y 465 | 466 | 467 | {-| 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`. 468 | 469 | foldl1 max [1,2,3,2,1] == Just 3 470 | foldl1 max [] == Nothing 471 | foldl1 (-) [1,2,3] == Just -4 472 | -} 473 | foldl1 : (a -> a -> a) -> List a -> Maybe a 474 | foldl1 f xs = 475 | let 476 | mf x m = Just (case m of 477 | Nothing -> x 478 | Just y -> f y x) 479 | in 480 | List.foldl mf Nothing xs 481 | 482 | {-| 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`. 483 | 484 | foldr1 min [1,2,3,2,1] == Just 1 485 | foldr1 min [] == Nothing 486 | foldr1 (-) [1,2,3] == Just 2 487 | -} 488 | foldr1 : (a -> a -> a) -> List a -> Maybe a 489 | foldr1 f xs = 490 | let 491 | mf x m = Just (case m of 492 | Nothing -> x 493 | Just y -> f x y) 494 | in 495 | List.foldr mf Nothing xs 496 | 497 | {-| `scanl1` is a variant of `scanl` that has no starting value argument. 498 | 499 | Compare: 500 | 501 | List.scanl (+) 0 [1,2,3] == [0,1,3,6] 502 | scanl1 (+) [1,2,3] == [1,3,6] 503 | 504 | List.scanl (-) 0 [1,2,3] == [0,1,1,2] 505 | scanl1 (-) [1,2,3] == [1,1,2] 506 | 507 | List.scanl (flip (-)) 0 [1,2,3] == [0,-1,-3,-6] 508 | scanl1 (flip (-)) [1,2,3] == [1,-1,4] 509 | -} 510 | scanl1 : (a -> a -> a) -> List a -> List a 511 | scanl1 f xs' = 512 | case xs' of 513 | [] -> [] 514 | (x::xs) -> scanl f x xs 515 | 516 | {-| `scanr` is a right-to-left dual of `scanl`. Note that: 517 | 518 | head (scanr f z xs) == foldr f z xs 519 | 520 | Examples: 521 | 522 | scanr (+) 0 [1,2,3] == [6,5,3,0] 523 | scanr (-) 0 [1,2,3] == [2,-1,3,0] 524 | -} 525 | scanr : (a -> b -> b) -> b -> List a -> List b 526 | scanr f acc xs' = 527 | case xs' of 528 | [] -> [acc] 529 | (x::xs) -> 530 | case scanr f acc xs of 531 | (q::_) as qs -> 532 | f x q :: qs 533 | 534 | [] -> 535 | [] 536 | 537 | {-| `scanr1` is a variant of `scanr` that has no starting value argument. 538 | 539 | scanr1 (+) [1,2,3] == [6,5,3] 540 | scanr1 (-) [1,2,3] == [2,-1,3] 541 | scanr1 (flip (-)) [1,2,3] == [0,1,3] 542 | -} 543 | scanr1 : (a -> a -> a) -> List a -> List a 544 | scanr1 f xs' = 545 | case xs' of 546 | [] -> [] 547 | [x] -> [x] 548 | (x::xs) -> 549 | case scanr1 f xs of 550 | (q::_) as qs -> 551 | f x q :: qs 552 | 553 | [] -> 554 | [] 555 | 556 | {-| 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. 557 | 558 | unfoldr (\b -> if b == 0 then Nothing else Just (b, b-1)) 5 == [5,4,3,2,1] 559 | -} 560 | unfoldr : (b -> Maybe (a, b)) -> b -> List a 561 | unfoldr f seed = 562 | case f seed of 563 | Nothing -> [] 564 | Just (a, b) -> a :: unfoldr f b 565 | 566 | {-| 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)`. 567 | 568 | splitAt 3 [1,2,3,4,5] == ([1,2,3],[4,5]) 569 | splitAt 1 [1,2,3] == ([1],[2,3]) 570 | splitAt 3 [1,2,3] == ([1,2,3],[]) 571 | splitAt 4 [1,2,3] == ([1,2,3],[]) 572 | splitAt 0 [1,2,3] == ([],[1,2,3]) 573 | splitAt (-1) [1,2,3] == ([],[1,2,3]) 574 | -} 575 | splitAt : Int -> List a -> (List a, List a) 576 | splitAt n xs = (take n xs, drop n xs) 577 | 578 | {-| Take elements from the end, while predicate still holds. 579 | 580 | takeWhileEnd ((<)5) [1..10] == [6,7,8,9,10] 581 | -} 582 | takeWhileEnd : (a -> Bool) -> List a -> List a 583 | takeWhileEnd p = 584 | let 585 | step x (xs,free) = if p x && free then (x::xs,True) else (xs, False) 586 | in 587 | fst << foldr step ([], True) 588 | 589 | {-| Drop elements from the end, while predicate still holds. 590 | 591 | dropWhileEnd ((<)5) [1..10] == [1,2,3,4,5] 592 | -} 593 | dropWhileEnd : (a -> Bool) -> List a -> List a 594 | dropWhileEnd p = foldr (\x xs -> if p x && isEmpty xs then [] else x::xs) [] 595 | 596 | {-| Take a predicate and a list, return a tuple. The first part of the tuple is 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)`. 597 | 598 | span (< 3) [1,2,3,4,1,2,3,4] == ([1,2],[3,4,1,2,3,4]) 599 | span (< 5) [1,2,3] == ([1,2,3],[]) 600 | span (< 0) [1,2,3] == ([],[1,2,3]) 601 | -} 602 | span : (a -> Bool) -> List a -> (List a, List a) 603 | span p xs = (takeWhile p xs, dropWhile p xs) 604 | 605 | {-| Take a predicate and a list, return a tuple. The first part of the tuple is 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. `span p xs` is equivalent to `(dropWhile p xs, takeWhile p xs)`. 606 | 607 | break (> 3) [1,2,3,4,1,2,3,4] == ([1,2,3],[4,1,2,3,4]) 608 | break (< 5) [1,2,3] == ([],[1,2,3]) 609 | break (> 5) [1,2,3] == ([1,2,3],[]) 610 | -} 611 | break : (a -> Bool) -> List a -> (List a, List a) 612 | break p = span (not << p) 613 | 614 | {-| Drop the given prefix from the list. If the list doesn't start with that prefix, return `Nothing`. 615 | 616 | stripPrefix [1,2] [1,2,3,4] == Just [3,4] 617 | stripPrefix [1,2,3] [1,2,3,4,5] == Just [4,5] 618 | stripPrefix [1,2,3] [1,2,3] == Just [] 619 | stripPrefix [1,2,3] [1,2] == Nothing 620 | stripPrefix [3,2,1] [1,2,3,4,5] == Nothing 621 | -} 622 | stripPrefix : List a -> List a -> Maybe (List a) 623 | stripPrefix prefix xs = 624 | let 625 | step e m = 626 | case m of 627 | Nothing -> Nothing 628 | Just [] -> Nothing 629 | Just (x::xs') -> if e == x 630 | then Just xs' 631 | else Nothing 632 | in 633 | foldl step (Just xs) prefix 634 | 635 | {-| Group similar elements together. `group` is equivalent to `groupWhile (==)`. 636 | 637 | group [1,2,2,3,3,3,2,2,1] == [[1],[2,2],[3,3,3],[2,2],[1]] 638 | -} 639 | group : List a -> List (List a) 640 | group = groupWhile (==) 641 | 642 | {-| Group elements together, using a custom equality test. 643 | 644 | groupWhile (\x y -> fst x == fst y) [(0,'a'),(0,'b'),(1,'c'),(1,'d')] == [[(0,'a'),(0,'b')],[(1,'c'),(1,'d')]] 645 | 646 | The equality test should be an equivalent relationship, i.e. it should have the properties of reflexivity, symmetry, and transitivity. For non-equivalent relations it gives non-intuitive behavior: 647 | 648 | groupWhile (<) [1,2,3,2,4,1,3,2,1] == [[1,2,3,2,4],[1,3,2],[1]] 649 | 650 | For grouping elements with a comparison test, which must only hold the property of transitivity, see `groupWhileTransitively`. 651 | -} 652 | groupWhile : (a -> a -> Bool) -> List a -> List (List a) 653 | groupWhile eq xs' = 654 | case xs' of 655 | [] -> [] 656 | (x::xs) -> let (ys,zs) = span (eq x) xs 657 | in (x::ys)::groupWhile eq zs 658 | 659 | {-| Group elements together, using a custom comparison test. Start a new group each time the comparison test doesn't hold for two adjacent elements. 660 | 661 | groupWhileTransitively (<) [1,2,3,2,4,1,3,2,1] == [[1,2,3],[2,4],[1,3],[2],[1]] 662 | -} 663 | groupWhileTransitively : (a -> a -> Bool) -> List a -> List (List a) 664 | groupWhileTransitively cmp xs' = 665 | case xs' of 666 | [] -> [] 667 | [x] -> [[x]] 668 | (x::((x'::_) as xs)) -> 669 | case groupWhileTransitively cmp xs of 670 | (y::ys) as r -> 671 | if cmp x x' 672 | then (x::y)::ys 673 | else [x]::r 674 | 675 | [] -> 676 | [] 677 | 678 | {-| Return all initial segments of a list, from shortest to longest, empty list first, the list itself last. 679 | 680 | inits [1,2,3] == [[],[1],[1,2],[1,2,3]] 681 | -} 682 | inits : List a -> List (List a) 683 | inits = foldr (\e acc -> []::map ((::)e) acc) [[]] 684 | 685 | {-| Return all final segments of a list, from longest to shortest, the list itself first, empty list last. 686 | 687 | tails [1,2,3] == [[1,2,3],[2,3],[3],[]] 688 | -} 689 | tails : List a -> List (List a) 690 | tails = foldr tailsHelp [[]] 691 | 692 | 693 | tailsHelp : a -> List (List a) -> List (List a) 694 | tailsHelp e list = 695 | case list of 696 | (x::xs) -> 697 | (e::x)::x::xs 698 | 699 | [] -> 700 | [] 701 | 702 | {-| 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. 703 | 704 | select [1,2,3,4] == [(1,[2,3,4]),(2,[1,3,4]),(3,[1,2,4]),(4,[1,2,3])] 705 | -} 706 | select : List a -> List (a, List a) 707 | select xs = 708 | case xs of 709 | [] -> [] 710 | (x::xs) -> (x,xs)::map (\(y,ys) -> (y,x::ys)) (select xs) 711 | 712 | {-| Return all combinations in the form of (elements before, element, elements after). 713 | 714 | selectSplit [1,2,3] == [([],1,[2,3]),([1],2,[3]),([1,2],3,[])] 715 | -} 716 | selectSplit : List a -> List (List a, a, List a) 717 | selectSplit xs = 718 | case xs of 719 | [] -> [] 720 | (x::xs) -> ([],x,xs)::map (\(lys,y,rys) -> (x::lys,y,rys)) (selectSplit xs) 721 | 722 | {-| Take 2 lists and return True, if the first list is the prefix of the second list. 723 | -} 724 | isPrefixOf : List a -> List a -> Bool 725 | isPrefixOf prefix = all identity << map2 (==) prefix 726 | 727 | {-| Take 2 lists and return True, if the first list is the suffix of the second list. 728 | -} 729 | isSuffixOf : List a -> List a -> Bool 730 | isSuffixOf suffix xs = isPrefixOf (reverse suffix) (reverse xs) 731 | 732 | {-| Take 2 lists and return True, if the first list is an infix of the second list. 733 | -} 734 | isInfixOf : List a -> List a -> Bool 735 | isInfixOf infix xs = any (isPrefixOf infix) (tails xs) 736 | 737 | {-| Take 2 lists and return True, if the first list is a subsequence of the second list. 738 | -} 739 | isSubsequenceOf : List a -> List a -> Bool 740 | isSubsequenceOf subseq xs = subseq `member` subsequences xs 741 | 742 | {-| Take 2 lists and return True, if the first list is a permutation of the second list. 743 | -} 744 | isPermutationOf : List a -> List a -> Bool 745 | isPermutationOf permut xs = permut `member` permutations xs 746 | 747 | {-| Take two lists and returns a list of corresponding pairs 748 | -} 749 | zip : List a -> List b -> List (a,b) 750 | zip = map2 (,) 751 | 752 | {-| Take three lists and returns a list of triples 753 | -} 754 | zip3 : List a -> List b -> List c -> List (a,b,c) 755 | zip3 = map3 (,,) 756 | 757 | {-| Take four lists and returns a list of quadruples 758 | -} 759 | zip4 : List a -> List b -> List c -> List d -> List (a,b,c,d) 760 | zip4 = map4 (,,,) 761 | 762 | {-| Take five lists and returns a list of quintuples 763 | -} 764 | zip5 : List a -> List b -> List c -> List d -> List e -> List (a,b,c,d,e) 765 | zip5 = map5 (,,,,) 766 | 767 | 768 | {-| Map functions taking multiple arguments over multiple lists, regardless of list length. 769 | All possible combinations will be explored. 770 | 771 | lift2 (+) [1,2,3] [4,5] == [5,6,6,7,7,8] 772 | -} 773 | lift2 : (a -> b -> c) -> List a -> List b -> List c 774 | lift2 f la lb = 775 | la `andThen` (\a -> lb `andThen` (\b -> [f a b])) 776 | 777 | {-| 778 | -} 779 | lift3 : (a -> b -> c -> d) -> List a -> List b -> List c -> List d 780 | lift3 f la lb lc = 781 | la `andThen` (\a -> lb `andThen` (\b -> lc `andThen` (\c -> [f a b c]))) 782 | 783 | {-| 784 | -} 785 | lift4 : (a -> b -> c -> d -> e) -> List a -> List b -> List c -> List d -> List e 786 | lift4 f la lb lc ld = 787 | la `andThen` (\a -> lb `andThen` (\b -> lc `andThen` (\c -> ld `andThen` (\d -> [f a b c d])))) 788 | 789 | {-| Split list into groups of size given by the first argument. 790 | 791 | groupsOf 3 [1..10] 792 | == [[1,2,3],[4,5,6],[7,8,9]] 793 | -} 794 | groupsOf : Int -> List a -> List (List a) 795 | groupsOf size xs = 796 | groupsOfWithStep size size xs 797 | 798 | 799 | {-| Split list into groups of size given by the first argument. After each group, drop a number of elements given by the second argumet before starting the next group. 800 | 801 | groupsOfWithStep 2 1 [1..4] 802 | == [[1,2],[2,3],[3,4]] 803 | -} 804 | groupsOfWithStep : Int -> Int -> List a -> List (List a) 805 | groupsOfWithStep size step xs = 806 | let 807 | group = 808 | List.take size xs 809 | 810 | xs' = 811 | List.drop step xs 812 | 813 | okayArgs = 814 | size > 0 && step > 0 815 | 816 | okayLength = 817 | size == List.length group 818 | in 819 | if okayArgs && okayLength then 820 | group :: groupsOfWithStep size step xs' 821 | else 822 | [] 823 | 824 | 825 | {-| Split list into groups of size given by the first argument "greedily" (don't throw the group away if not long enough). 826 | 827 | greedyGroupsOf 3 [1..10] 828 | == [[1,2,3],[4,5,6],[7,8,9],[10]] 829 | -} 830 | greedyGroupsOf : Int -> List a -> List (List a) 831 | greedyGroupsOf size xs = 832 | greedyGroupsOfWithStep size size xs 833 | 834 | 835 | {-| Split list into groups of size given by the first argument "greedily" (don't throw the group away if not long enough). After each group, drop a number of elements given by the second argumet before starting the next group. 836 | 837 | greedyGroupsOfWithStep 3 2 [1..6] 838 | == [[1,2,3],[3,4,5],[5,6]] 839 | -} 840 | greedyGroupsOfWithStep : Int -> Int -> List a -> List (List a) 841 | greedyGroupsOfWithStep size step xs = 842 | let 843 | group = 844 | List.take size xs 845 | 846 | xs' = 847 | List.drop step xs 848 | 849 | okayArgs = 850 | size > 0 && step > 0 851 | 852 | okayXs = 853 | List.length xs > 0 854 | in 855 | if okayArgs && okayXs then 856 | group :: greedyGroupsOfWithStep size step xs' 857 | else 858 | [] 859 | --------------------------------------------------------------------------------