From a831702c3cd67232a32d783d2643bdda264bc4bf Mon Sep 17 00:00:00 2001 From: Joshua Horowitz Date: Thu, 19 Jan 2017 16:16:41 -0800 Subject: [PATCH 1/4] Add unsnoc --- src/Data/List.purs | 8 ++++++++ test/Test/Data/List.purs | 13 ++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Data/List.purs b/src/Data/List.purs index 3940020..d4dc06c 100644 --- a/src/Data/List.purs +++ b/src/Data/List.purs @@ -31,6 +31,7 @@ module Data.List , tail , init , uncons + , unsnoc , (!!), index , elemIndex @@ -257,6 +258,13 @@ 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(2n)` +unsnoc :: forall a. List a -> Maybe { init :: List a, last :: a } +unsnoc xs = { init: _, last: _ } <$> init xs <*> last xs + -------------------------------------------------------------------------------- -- 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) From 919d3adabdc16ec6ecf197200045f88aa6dc68fc Mon Sep 17 00:00:00 2001 From: Joshua Horowitz Date: Thu, 19 Jan 2017 23:24:20 -0800 Subject: [PATCH 2/4] Implement unsnoc in a single pass --- src/Data/List.purs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Data/List.purs b/src/Data/List.purs index d4dc06c..0fbb02e 100644 --- a/src/Data/List.purs +++ b/src/Data/List.purs @@ -243,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. @@ -261,9 +256,14 @@ 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(2n)` +-- | Running time: `O(n)` unsnoc :: forall a. List a -> Maybe { init :: List a, last :: a } -unsnoc xs = { init: _, last: _ } <$> init xs <*> last xs +unsnoc lst = unsnocHelper lst Nil <#> \h -> { init: reverse h.revInit, last: h.last } + +unsnocHelper :: forall a. List a -> List a -> Maybe { revInit :: List a, last :: a } +unsnocHelper Nil acc = Nothing +unsnocHelper (x : Nil) acc = Just { revInit: acc, last: x } +unsnocHelper (x : xs) acc = unsnocHelper xs (x : acc) -------------------------------------------------------------------------------- -- Indexed operations ---------------------------------------------------------- From 2ef161dd2c52d31b4de48d9ed086040b9dc500f5 Mon Sep 17 00:00:00 2001 From: Joshua Horowitz Date: Fri, 20 Jan 2017 12:39:19 -0800 Subject: [PATCH 3/4] unsnocHelper => go --- src/Data/List.purs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Data/List.purs b/src/Data/List.purs index 0fbb02e..80c0b12 100644 --- a/src/Data/List.purs +++ b/src/Data/List.purs @@ -258,12 +258,11 @@ uncons (x : xs) = Just { head: x, tail: xs } -- | -- | Running time: `O(n)` unsnoc :: forall a. List a -> Maybe { init :: List a, last :: a } -unsnoc lst = unsnocHelper lst Nil <#> \h -> { init: reverse h.revInit, last: h.last } - -unsnocHelper :: forall a. List a -> List a -> Maybe { revInit :: List a, last :: a } -unsnocHelper Nil acc = Nothing -unsnocHelper (x : Nil) acc = Just { revInit: acc, last: x } -unsnocHelper (x : xs) acc = unsnocHelper xs (x : acc) +unsnoc lst = go lst Nil <#> \h -> { init: reverse h.revInit, last: h.last } + where + go Nil acc = Nothing + go (x : Nil) acc = Just { revInit: acc, last: x } + go (x : xs) acc = go xs (x : acc) -------------------------------------------------------------------------------- -- Indexed operations ---------------------------------------------------------- From ad42fab066dfff36d48beb6713ad342166e7bdfb Mon Sep 17 00:00:00 2001 From: Joshua Horowitz Date: Fri, 20 Jan 2017 16:31:33 -0800 Subject: [PATCH 4/4] More consistent style --- src/Data/List.purs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Data/List.purs b/src/Data/List.purs index 80c0b12..0707822 100644 --- a/src/Data/List.purs +++ b/src/Data/List.purs @@ -258,11 +258,11 @@ uncons (x : xs) = Just { head: x, tail: xs } -- | -- | Running time: `O(n)` unsnoc :: forall a. List a -> Maybe { init :: List a, last :: a } -unsnoc lst = go lst Nil <#> \h -> { init: reverse h.revInit, last: h.last } +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) + go Nil acc = Nothing + go (x : Nil) acc = Just { revInit: acc, last: x } + go (x : xs) acc = go xs (x : acc) -------------------------------------------------------------------------------- -- Indexed operations ----------------------------------------------------------