diff --git a/src/Data/List.purs b/src/Data/List.purs index 3940020..0707822 100644 --- a/src/Data/List.purs +++ b/src/Data/List.purs @@ -31,6 +31,7 @@ module Data.List , tail , init , uncons + , unsnoc , (!!), index , elemIndex @@ -242,12 +243,7 @@ tail (_ : xs) = Just xs -- | -- | Running time: `O(n)` init :: forall a. List a -> Maybe (List a) -init Nil = Nothing -init lst = Just $ reverse $ go lst Nil - where - go (x : Nil) acc = acc - go (x : xs) acc = go xs (x : acc) - go _ acc = acc +init lst = _.init <$> unsnoc lst -- | Break a list into its first element, and the remaining elements, -- | or `Nothing` if the list is empty. @@ -257,6 +253,17 @@ uncons :: forall a. List a -> Maybe { head :: a, tail :: List a } uncons Nil = Nothing uncons (x : xs) = Just { head: x, tail: xs } +-- | Break a list into its last element, and the preceding elements, +-- | or `Nothing` if the list is empty. +-- | +-- | Running time: `O(n)` +unsnoc :: forall a. List a -> Maybe { init :: List a, last :: a } +unsnoc lst = (\h -> { init: reverse h.revInit, last: h.last }) <$> go lst Nil + where + go Nil acc = Nothing + go (x : Nil) acc = Just { revInit: acc, last: x } + go (x : xs) acc = go xs (x : acc) + -------------------------------------------------------------------------------- -- Indexed operations ---------------------------------------------------------- -------------------------------------------------------------------------------- diff --git a/test/Test/Data/List.purs b/test/Test/Data/List.purs index 8eb5758..fadb1eb 100644 --- a/test/Test/Data/List.purs +++ b/test/Test/Data/List.purs @@ -5,7 +5,7 @@ import Data.List.NonEmpty as NEL import Control.Monad.Eff (Eff) import Control.Monad.Eff.Console (CONSOLE, log) import Data.Foldable (foldMap, foldl) -import Data.List (List(..), (..), length, range, foldM, unzip, zip, zipWithA, zipWith, intersectBy, intersect, (\\), deleteBy, delete, unionBy, union, nubBy, nub, groupBy, group', group, span, dropWhile, drop, takeWhile, take, sortBy, sort, catMaybes, mapMaybe, filterM, filter, concat, concatMap, reverse, alterAt, modifyAt, updateAt, deleteAt, insertAt, findLastIndex, findIndex, elemLastIndex, elemIndex, (!!), uncons, init, tail, last, head, insertBy, insert, snoc, null, singleton, fromFoldable, transpose, mapWithIndex, (:)) +import Data.List (List(..), (..), length, range, foldM, unzip, zip, zipWithA, zipWith, intersectBy, intersect, (\\), deleteBy, delete, unionBy, union, nubBy, nub, groupBy, group', group, span, dropWhile, drop, takeWhile, take, sortBy, sort, catMaybes, mapMaybe, filterM, filter, concat, concatMap, reverse, alterAt, modifyAt, updateAt, deleteAt, insertAt, findLastIndex, findIndex, elemLastIndex, elemIndex, (!!), uncons, unsnoc, init, tail, last, head, insertBy, insert, snoc, null, singleton, fromFoldable, transpose, mapWithIndex, (:)) import Data.Maybe (Maybe(..), isNothing, fromJust) import Data.Monoid.Additive (Additive(..)) import Data.NonEmpty ((:|)) @@ -106,6 +106,17 @@ testList = do assert $ unsafePartial (fromJust u2).head == 1 assert $ unsafePartial (fromJust u2).tail == l [2, 3] + log "unsnoc should return nothing when used on an empty list" + assert $ isNothing (unsnoc nil) + + log "unsnoc should split an list into an init and last record when there is at least one item" + let v1 = unsnoc (l [1]) + assert $ unsafePartial (fromJust v1).init == l [] + assert $ unsafePartial (fromJust v1).last == 1 + let v2 = unsnoc (l [1, 2, 3]) + assert $ unsafePartial (fromJust v2).init == l [1, 2] + assert $ unsafePartial (fromJust v2).last == 3 + log "(!!) should return Just x when the index is within the bounds of the list" assert $ l [1, 2, 3] !! 0 == (Just 1) assert $ l [1, 2, 3] !! 1 == (Just 2)