This is an alternative site for discovering Elm packages. You may be looking for the official Elm package site instead.
1.0.0
README

List.Experimental

List.Experimental is a testing playground for various List related functions. It contains functions that are experimental, unidiomatic, controversial or downright silly. This is specifically to not clutter List and List.Extra, and also have an isolated place to test crazy ideas.

Do not use this module in production code. Try your best to come up with equivalent functionality or solve your problem in a different way, and if you fail, consider contributing to List and List.Extra packages.

Do not import functions from this module unqualified if you do use it.

This package has the lowest possible bar for inclusion of List related functions. If you have some code that you want to publish somewhere, but not necessarily contribute to core libraries, feel absolutely free to contribute here. Treat this package as a safe sandbox. The GitHub page for ideas, suggestions, discussions, and pull requests is:

https://github.com/sindikat/elm-list-experimental

List functions

and : List Bool -> Bool

Return the conjunction of all Bools in a list. In other words, return True if all elements are True, return False otherwise. and is equivalent to all identity. Return True on an empty list.

or : List Bool -> Bool

Return the disjunction of all Bools in a list. In other words, return True if any element is True, return False otherwise. or is equivalent to any identity. Return False on an empty list.

conjunction : List Bool -> Bool

Same as and.

disjunction : List Bool -> Bool

Same as or.

lookup : a -> List ( a, b ) -> Maybe b

Look up a key in an association list, return corresponding value, wrapped in Just. If no value is found, return Nothing. If multiple values correspond to the same key, return the first found value.

lookup 'a' [('a',1),('b',2),('c',3)] == Just 1
lookup 'd' [('a',1),('b',2),('c',3)] == Nothing
lookup 3 [(1,"John"),(1,"Paul"),(2,"Mary")] == Just "John"
filter2 : (a -> b -> Bool) -> List a -> List b -> List ( a, b )

Filter over two lists simultaneously using a custom comparison function, return a list of pairs.

filterMap2 : (a -> b -> Maybe c) -> List a -> List b -> List c

Apply a function, which may succeed, to all values of two lists, but only keep the successes.

filterM : (a -> List Bool) -> List a -> List (List a)

Filter that exploits the behavior of andThen.

Return all subsequences of a list:

filterM (\x -> [True, False]) [1,2,3] == [[1,2,3],[1,2],[1,3],[1],[2,3],[2],[3],[]]

Return all subsequences that contain 2:

filterM (\x -> if x==2 then [True] else [True,False]) [1,2,3] == [[1,2,3],[1,2],[2,3],[2]]

Elements

at : Int -> List a -> Maybe a

Extract nth element of a list, index counts from 0.

at 1 [1,2,3] == Just 2
at 3 [1,2,3] == Nothing
at -1 [1,2,3] == Nothing

Removal

removeAt : Int -> List a -> List a

Remove nth element of a list. If index is negative or out of bounds of the list, return the list unchanged.

removeAt 0 [1,2,3] == [2,3]
removeAt 3 [1,2,3] == [1,2,3]
removeAt -1 [1,2,3] == [1,2,3]
removeFirst : a -> List a -> List a

Remove first occurrence of element from list.

removeFirst 2 [1,2,1,2] == [1,1,2]
removeFirstBy : (a -> a -> Bool) -> a -> List a -> List a

Generic version of removeFirst with a custom predicate. For example, remove first element that is greater than 2:

removeFirstBy (>) 2 [1..4] == [1,2,4]
removeFirsts : List a -> List a -> List a

Remove first occurence of each element from list.

removeFirsts [1,2] [1,2,3,1,2,3] == [3,1,2,3]
removeFirstsBy : (a -> a -> Bool) -> List a -> List a -> List a

Generic version of removeFirsts with a custom predicate. For example, remove first element that evenly divides by 2, then remove first element that evenly divides by 3:

removeFirstsBy (\a b -> a `rem` b == 0) [2,3] [5..10] == [5,7,8,10]

Set functions

difference : List a -> List a -> List a

Set difference between lists.

[1,2,3] `difference` [3,4,5] == [1,2]
union : List a -> List a -> List a

Union between lists.

[3,2,1] union [3,4,5] == [3,2,1,4,5]

intersect : List a -> List a -> List a

Intersection between lists.

[1,2,3] intersect [3,4,5] == [3]

insert : comparable -> List comparable -> List comparable

Take an element and a list and insert the element into the list at the first position where it is less than or equal to the next element. If the list is sorted before the call, the result will also be sorted.

insert 4 [1,3,5] == [1,3,4,5]

differenceBy : (a -> a -> Bool) -> List a -> List a -> List a

Generic version of difference with a custom predicate.

unionBy : (a -> a -> Bool) -> List a -> List a -> List a

Generic version of union with a custom predicate.

intersectBy : (a -> a -> Bool) -> List a -> List a -> List a

Generic version of intersect with a custom predicate.

insertBy : (a -> a -> Order) -> a -> List a -> List a

Generic version of insert with a custom predicate.

Misc

iterate : Int -> (a -> a) -> a -> List a

Return a list of repeated applications of f to x.

module List.Experimental
    exposing
        ( and
        , or
        , conjunction
        , disjunction
        , lookup
        , filter2
        , filterMap2
        , filterM
        , at
        , removeAt
        , removeFirst
        , removeFirstBy
        , removeFirsts
        , removeFirstsBy
        , difference
        , union
        , intersect
        , insert
        , differenceBy
        , unionBy
        , intersectBy
        , insertBy
        , iterate
        )

{-| List.Experimental is a testing playground for various List related functions. It contains functions that are experimental, unidiomatic, controversial or downright silly. This is specifically to not clutter List and List.Extra, and also have an isolated place to test crazy ideas.

*Do not* use this module in production code. Try your best to come up with equivalent functionality or solve your problem in a different way, and if you fail, consider contributing to List and List.Extra packages.

*Do not* import functions from this module unqualified if you do use it.

This package has the lowest possible bar for inclusion of List related functions. If you have some code that you want to publish somewhere, but not necessarily contribute to core libraries, feel absolutely free to contribute here. Treat this package as a safe sandbox. The GitHub page for ideas, suggestions, discussions, and pull requests is:

https://github.com/sindikat/elm-list-experimental

# List functions
@docs and, or, conjunction, disjunction, lookup, filter2, filterMap2, filterM

# Elements
@docs at

# Removal
@docs removeAt, removeFirst, removeFirstBy, removeFirsts, removeFirstsBy

# Set functions
@docs difference, union, intersect, insert, differenceBy, unionBy, intersectBy, insertBy

# Misc
@docs iterate
-}

import List exposing (..)
import List.Extra exposing (..)


{-| Return the conjunction of all `Bool`s in a list. In other words, return True if all elements are True, return False otherwise. `and` is equivalent to `all identity`. Return True on an empty list.
-}
and : List Bool -> Bool
and =
    all identity


{-| Return the disjunction of all `Bool`s in a list. In other words, return True if any element is True, return False otherwise. `or` is equivalent to `any identity`. Return False on an empty list.
-}
or : List Bool -> Bool
or =
    any identity


{-| Same as `and`.
-}
conjunction : List Bool -> Bool
conjunction =
    and


{-| Same as `or`.
-}
disjunction : List Bool -> Bool
disjunction =
    or


{-| Look up a key in an association list, return corresponding value, wrapped in `Just`. If no value is found, return `Nothing`. If multiple values correspond to the same key, return the first found value.

    lookup 'a' [('a',1),('b',2),('c',3)] == Just 1
    lookup 'd' [('a',1),('b',2),('c',3)] == Nothing
    lookup 3 [(1,"John"),(1,"Paul"),(2,"Mary")] == Just "John"
-}
lookup : a -> List ( a, b ) -> Maybe b
lookup key =
    Maybe.map snd << find (\item -> fst item == key)


{-| Filter over two lists simultaneously using a custom comparison function, return a list of pairs.
-}
filter2 : (a -> b -> Bool) -> List a -> List b -> List ( a, b )
filter2 p xs ys =
    filter (uncurry p) (map2 (,) xs ys)


{-| Apply a function, which may succeed, to all values of two lists, but only keep the successes.
-}
filterMap2 : (a -> b -> Maybe c) -> List a -> List b -> List c
filterMap2 f xs ys =
    List.filterMap identity <| map2 f xs ys


{-| Filter that exploits the behavior of `andThen`.

Return all subsequences of a list:

    filterM (\x -> [True, False]) [1,2,3] == [[1,2,3],[1,2],[1,3],[1],[2,3],[2],[3],[]]

Return all subsequences that contain 2:

    filterM (\x -> if x==2 then [True] else [True,False]) [1,2,3] == [[1,2,3],[1,2],[2,3],[2]]

-}
filterM : (a -> List Bool) -> List a -> List (List a)
filterM p =
    let
        andThen =
            flip concatMap

        go x r =
            p x
                `andThen`
                    (\flg ->
                        r
                            `andThen`
                                (\ys ->
                                    [ if flg then
                                        x :: ys
                                      else
                                        ys
                                    ]
                                )
                    )
    in
        foldr go [ [] ]



-- come up with a better name?


{-| Extract *n*th element of a list, index counts from 0.

    at 1 [1,2,3] == Just 2
    at 3 [1,2,3] == Nothing
    at -1 [1,2,3] == Nothing
-}
at : Int -> List a -> Maybe a
at n xs =
    if n >= 0 then
        head <| drop n xs
    else
        Nothing


{-| Remove *n*th element of a list. If index is negative or out of bounds of the list, return the list unchanged.

    removeAt 0 [1,2,3] == [2,3]
    removeAt 3 [1,2,3] == [1,2,3]
    removeAt -1 [1,2,3] == [1,2,3]
-}
removeAt : Int -> List a -> List a
removeAt n xs =
    take n xs ++ drop (n + 1) xs


{-| Remove first occurrence of element from list.

    removeFirst 2 [1,2,1,2] == [1,1,2]
-}
removeFirst : a -> List a -> List a
removeFirst =
    removeFirstBy (==)


{-| Remove first occurence of each element from list.

    removeFirsts [1,2] [1,2,3,1,2,3] == [3,1,2,3]
-}
removeFirsts : List a -> List a -> List a
removeFirsts =
    removeFirstsBy (==)


{-| Remove last occurrence of element from list.

    removeLast 2 [1,2,1,2] == [1,2,1]
-}
removeLast : a -> List a -> List a
removeLast =
    removeLastBy (==)


{-| Generic version of removeFirst with a custom predicate. For example, remove first element that is greater than 2:

    removeFirstBy (>) 2 [1..4] == [1,2,4]
-}
removeFirstBy : (a -> a -> Bool) -> a -> List a -> List a
removeFirstBy eq x xs =
    let
        ( ys, zs ) =
            break (flip eq x) xs
    in
        ys ++ drop 1 zs


{-| Generic version of removeFirsts with a custom predicate. For example, remove first element that evenly divides by 2, then remove first element that evenly divides by 3:

    removeFirstsBy (\a b -> a `rem` b == 0) [2,3] [5..10] == [5,7,8,10]
-}
removeFirstsBy : (a -> a -> Bool) -> List a -> List a -> List a
removeFirstsBy eq =
    flip <| foldl (removeFirstBy eq)


{-| Generic version of removeLast with a custom predicate.
-}
removeLastBy : (a -> a -> Bool) -> a -> List a -> List a
removeLastBy eq x =
    List.reverse << removeFirstBy eq x << List.reverse


{-| Set difference between lists.

    [1,2,3] `difference` [3,4,5] == [1,2]
-}
difference : List a -> List a -> List a
difference =
    differenceBy (==)


{-| Union between lists.

   [3,2,1] `union` [3,4,5] == [3,2,1,4,5]
-}
union : List a -> List a -> List a
union =
    unionBy (==)


{-| Intersection between lists.

   [1,2,3] `intersect` [3,4,5] == [3]
-}
intersect : List a -> List a -> List a
intersect =
    intersectBy (==)


{-| Take an element and a list and insert the element into the list at the first position where it is less than or equal to the next element. If the list is sorted before the call, the result will also be sorted.

   insert 4 [1,3,5] == [1,3,4,5]
-}
insert : comparable -> List comparable -> List comparable
insert =
    insertBy compare


{-| Generic version of difference with a custom predicate.
-}
differenceBy : (a -> a -> Bool) -> List a -> List a -> List a
differenceBy eq xs ys =
    filter (\x -> not <| any (eq x) ys) xs


{-| Generic version of union with a custom predicate.
-}
unionBy : (a -> a -> Bool) -> List a -> List a -> List a
unionBy eq xs ys =
    xs ++ filter (\y -> not <| any (eq y) xs) ys


{-| Generic version of intersect with a custom predicate.
-}
intersectBy : (a -> a -> Bool) -> List a -> List a -> List a
intersectBy eq xs ys =
    filter (\y -> any (eq y) xs) ys



-- insertWith?


{-| Generic version of insert with a custom predicate.
-}
insertBy : (a -> a -> Order) -> a -> List a -> List a
insertBy cmp e xs =
    let
        ( ys, zs ) =
            break (\x -> cmp e x == GT) xs
    in
        ys ++ [ e ] ++ zs


{-| Return a list of repeated applications of `f` to `x`.
-}
iterate : Int -> (a -> a) -> a -> List a
iterate n f x =
    let
        step ( n, x' ) =
            if n == 0 then
                Nothing
            else
                Just ( x', ( n - 1, f x' ) )
    in
        unfoldr step ( n, x )



-- move to extra?


{-| -}
unzip3 : List ( a, b, c ) -> ( List a, List b, List c )
unzip3 pairs =
    let
        step ( x, y, z ) ( xs, ys, zs ) =
            ( x :: xs, y :: ys, z :: zs )
    in
        foldr step ( [], [], [] ) pairs


{-| -}
unzip4 : List ( a, b, c, d ) -> ( List a, List b, List c, List d )
unzip4 pairs =
    let
        step ( w, x, y, z ) ( ws, xs, ys, zs ) =
            ( w :: ws, x :: xs, y :: ys, z :: zs )
    in
        foldr step ( [], [], [], [] ) pairs


{-| -}
unzip5 : List ( a, b, c, d, e ) -> ( List a, List b, List c, List d, List e )
unzip5 pairs =
    let
        step ( v, w, x, y, z ) ( vs, ws, xs, ys, zs ) =
            ( v :: vs, w :: ws, x :: xs, y :: ys, z :: zs )
    in
        foldr step ( [], [], [], [], [] ) pairs


mapWhen : (a -> Bool) -> (a -> a) -> List a -> List a
mapWhen p f xs =
    map
        (\x ->
            if p x then
                f x
            else
                x
        )
        xs



-- mapFirst : (a -> Bool) -> (a -> a) -> List a -> List a
-- mapFirst p f xs =
--   let
--     (ys, zs) = span p xs
--   in
-- mapLast : (a -> Bool) -> (a -> a) -> List a -> List a
-- mapLast


annonate : (a -> b) -> List a -> List ( b, a )
annonate f xs =
    map (\x -> ( f x, x )) xs


splice : (a -> Bool) -> (a -> List a) -> List a -> List a
splice p f xs =
    concatMap
        (\x ->
            if p x then
                f x
            else
                [ x ]
        )
        xs


spliceList : (a -> Bool) -> List a -> List a -> List a
spliceList p ys xs =
    splice p (always ys) xs


selectByIndices : List Int -> List a -> List a
selectByIndices ns xs =
    filterMap (\n -> at n xs) ns