{-| Module : List Description : Work with lists. License : BSD 3 Maintainer : terezasokol@gmail.com Stability : experimental Portability : POSIX -} module List ( -- * Create List, singleton, repeat, range -- * Transform , map, indexedMap, foldl, foldr, filter, filterMap -- * Utilities , length, reverse, member, all, any, maximum, minimum, sum, product -- * Combine , append, concat, concatMap, intersperse, map2, map3, map4, map5 -- * Sort , sort, sortBy, sortWith -- * Deconstruct , isEmpty, head, tail, take, drop, partition, unzip ) where import Prelude (Applicative, Char, Eq, Functor, Monad, Num, Ord, Show, Bool(..), Int, Ordering, (-), flip, mappend, mconcat) import Maybe (Maybe (..)) import qualified Prelude import qualified Data.List import qualified Data.Maybe import qualified Internal.Shortcut as Shortcut {-| A list. -} type List a = [a] -- CREATE {-| Create a list with only one element: > singleton 1234 == [1234] > singleton "hi" == ["hi"] -} singleton :: a -> List a singleton value = [value] {-| Create a list with *n* copies of a value: > repeat 3 (0,0) == [(0,0),(0,0),(0,0)] -} repeat :: Int -> a -> List a repeat = Data.List.replicate {-| Create a list of numbers, every element increasing by one. You give the lowest and highest number that should be in the list. > range 3 6 == [3, 4, 5, 6] > range 3 3 == [3] > range 6 3 == [] -} range :: Int -> Int -> List Int range lo hi = [lo .. hi] -- TRANSFORM {-| Apply a function to every element of a list. > map sqrt [1,4,9] == [1,2,3] > > map not [True,False,True] == [False,True,False] So `map func [ a, b, c ]` is the same as `[ func a, func b, func c ]` -} map :: (a -> b) -> List a -> List b map = Prelude.fmap {-| Same as `map` but the function is also applied to the index of each element (starting at zero). > indexedMap Tuple.pair ["Tom","Sue","Bob"] == [ (0,"Tom"), (1,"Sue"), (2,"Bob") ] -} indexedMap :: (Int -> a -> b) -> List a -> List b indexedMap f xs = List.map2 f [0 .. (length xs - 1)] xs {-| Reduce a list from the left. > foldl (+) 0 [1,2,3] == 6 > foldl (::) [] [1,2,3] == [3,2,1] So 'foldl step state [1,2,3]' is like saying: > state > |> step 1 > |> step 2 > |> step 3 -} foldl :: (a -> b -> b) -> b -> List a -> b foldl func = -- Note: This function is implemented using fold' to eagerly evaluate the -- accumulator, preventing space leaks. Data.List.foldl' (flip func) {-| Reduce a list from the right. > foldr (+) 0 [1,2,3] == 6 > foldr (::) [] [1,2,3] == [1,2,3] So `foldr step state [1,2,3]` is like saying: > state > |> step 3 > |> step 2 > |> step 1 -} foldr :: (a -> b -> b) -> b -> List a -> b foldr = Data.List.foldr {-| Keep elements that satisfy the test. > filter isEven [1,2,3,4,5,6] == [2,4,6] -} filter :: (a -> Bool) -> List a -> List a filter = Data.List.filter {-| Filter out certain values. For example, maybe you have a bunch of strings from an untrusted source and you want to turn them into numbers: > numbers :: List Int > numbers = > filterMap String.toInt ["3", "hi", "12", "4th", "May"] > > -- numbers == [3, 12] -} filterMap :: (a -> Maybe b) -> List a -> List b filterMap toMaybe = Data.Maybe.mapMaybe (\a -> toHMaybe (toMaybe a)) -- UTILITIES {-| Determine the length of a list. > length [1,2,3] == 3 -} length :: List a -> Int length = Data.List.length {-| Reverse a list. > reverse [1,2,3,4] == [4,3,2,1] -} reverse :: List a -> List a reverse = Data.List.reverse {-| Figure out whether a list contains a value. > member 9 [1,2,3,4] == False > member 4 [1,2,3,4] == True -} member :: Prelude.Eq a => a -> List a -> Bool member = Data.List.elem {-| Determine if all elements satisfy some test. > all isEven [2,4] == True > all isEven [2,3] == False > all isEven [] == True -} all :: (a -> Bool) -> List a -> Bool all = Data.List.all {-| Determine if any elements satisfy some test. > any isEven [2,3] == True > any isEven [1,3] == False > any isEven [] == False -} any :: (a -> Bool) -> List a -> Bool any = Data.List.any {-| Find the maximum element in a non-empty list. > maximum [1,4,2] == Just 4 > maximum [] == Nothing -} maximum :: Prelude.Ord a => List a -> Maybe a maximum list = case list of [] -> Nothing _ -> Just (Data.List.maximum list) {-| Find the minimum element in a non-empty list. > minimum [3,2,1] == Just 1 > minimum [] == Nothing -} minimum :: Prelude.Ord a => List a -> Maybe a minimum list = case list of [] -> Nothing _ -> Just (Data.List.minimum list) {-| Get the sum of the list elements. > sum [1,2,3] == 6 > sum [1,1,1] == 3 > sum [] == 0 -} sum :: Prelude.Num a => List a -> a sum = Prelude.sum {-| Get the product of the list elements. > product [2,2,2] == 8 > product [3,3,3] == 27 > product [] == 1 -} product :: Prelude.Num a => List a -> a product = Prelude.product -- COMBINE {-| Put two lists together. > append [1,1,2] [3,5,8] == [1,1,2,3,5,8] > append ['a','b'] ['c'] == ['a','b','c'] You can also use [the `(++)` operator](Basics#++) to append lists. -} append :: List a -> List a -> List a append = Prelude.mappend {-| Concatenate a bunch of lists into a single list: > concat [[1,2],[3],[4,5]] == [1,2,3,4,5] -} concat :: List (List a) -> List a concat = Prelude.mconcat {-| Map a given function onto a list and flatten the resulting lists. > concatMap f xs == concat (map f xs) -} concatMap :: (a -> List b) -> List a -> List b concatMap = Shortcut.andThen {-| Places the given value between all members of the given list. > intersperse "on" ["turtles","turtles","turtles"] == ["turtles","on","turtles","on","turtles"] -} intersperse :: a -> List a -> List a intersperse = Data.List.intersperse {-| Combine two lists, combining them with the given function. If one list is longer, the extra elements are dropped. > totals :: List Int -> List Int -> List Int > totals xs ys = > List.map2 (+) xs ys > > -- totals [1,2,3] [4,5,6] == [5,7,9] > > pairs :: List a -> List b -> List (a,b) > pairs xs ys = > List.map2 Tuple.pair xs ys > > -- pairs ["alice","bob","chuck"] [2,5,7,8] > -- == [("alice",2),("bob",5),("chuck",7)] -} map2 :: (a -> b -> result) -> List a -> List b -> List result map2 = Data.List.zipWith {-| -} map3 :: (a -> b -> c -> result) -> List a -> List b -> List c -> List result map3 = Data.List.zipWith3 {-| -} map4 :: (a -> b -> c -> d -> result) -> List a -> List b -> List c -> List d -> List result map4 = Data.List.zipWith4 {-| -} map5 :: (a -> b -> c -> d -> e -> result) -> List a -> List b -> List c -> List d -> List e -> List result map5 = Data.List.zipWith5 -- SORT {-| Sort values from lowest to highest sort [3,1,5] == [1,3,5] -} sort :: Prelude.Ord a => List a -> List a sort = Data.List.sort {-| Sort values by a derived property. > alice = { name="Alice", height=1.62 } > bob = { name="Bob" , height=1.85 } > chuck = { name="Chuck", height=1.76 } > > sortBy .name [chuck,alice,bob] == [alice,bob,chuck] > sortBy .height [chuck,alice,bob] == [alice,chuck,bob] > > sortBy String.length ["mouse","cat"] == ["cat","mouse"] -} sortBy :: Prelude.Ord b => (a -> b) -> List a -> List a sortBy = Data.List.sortOn {-| Sort values with a custom comparison function. > sortWith flippedComparison [1,2,3,4,5] == [5,4,3,2,1] > > flippedComparison a b = > case compare a b of > LT -> GT > EQ -> EQ > GT -> LT This is also the most general sort function, allowing you to define any other: `sort == sortWith compare` -} sortWith :: (a -> a -> Ordering) -> List a -> List a sortWith = Data.List.sortBy -- DECONSTRUCT {-| Determine if a list is empty. > isEmpty [] == True Note: It is usually preferable to use a `case` to test this so you do not forget to handle the `(x :: xs)` case as well! -} isEmpty :: List a -> Bool isEmpty = Data.List.null {-| Extract the first element of a list. > head [1,2,3] == Just 1 > head [] == Nothing Note: It is usually preferable to use a `case` to deconstruct a `List` because it gives you `(x :: xs)` and you can work with both subparts. -} head :: List a -> Maybe a head xs = case xs of x : _ -> Just x [] -> Nothing {-| Extract the rest of the list. > tail [1,2,3] == Just [2,3] > tail [] == Nothing Note: It is usually preferable to use a `case` to deconstruct a `List` because it gives you `(x :: xs)` and you can work with both subparts. -} tail :: List a -> Maybe (List a) tail list = case list of _ : xs -> Just xs [] -> Nothing {-| Take the first *n* members of a list. > take 2 [1,2,3,4] == [1,2] -} take :: Int -> List a -> List a take = Data.List.take {-| Drop the first *n* members of a list. > drop 2 [1,2,3,4] == [3,4] -} drop :: Int -> List a -> List a drop = Data.List.drop {-| Partition a list based on some test. The first list contains all values that satisfy the test, and the second list contains all the value that do not. > partition (\x -> x < 3) [0,1,2,3,4,5] == ([0,1,2], [3,4,5]) > partition isEven [0,1,2,3,4,5] == ([0,2,4], [1,3,5]) -} partition :: (a -> Bool) -> List a -> (List a, List a) partition = Data.List.partition {-| Decompose a list of tuples into a tuple of lists. > unzip [(0, True), (17, False), (1337, True)] == ([0,17,1337], [True,False,True]) -} unzip :: List (a, b) -> (List a, List b) unzip = Data.List.unzip -- INTERNAL toHMaybe :: Maybe a -> Data.Maybe.Maybe a toHMaybe maybe = case maybe of Just a -> Data.Maybe.Just a Nothing -> Data.Maybe.Nothing