From e5e3f8f006838ac5aa3aff64f9dbb37cae9a3728 Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Tue, 27 Jun 2017 21:32:47 +0400 Subject: [PATCH] add stripPrefix for List.Lazy --- src/Data/List/Lazy.purs | 39 ++++++++++++++++++++++++++++++----- test/Test/Data/List/Lazy.purs | 6 +++++- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/Data/List/Lazy.purs b/src/Data/List/Lazy.purs index 69f80aa..8f9f5ef 100644 --- a/src/Data/List/Lazy.purs +++ b/src/Data/List/Lazy.purs @@ -57,6 +57,8 @@ module Data.List.Lazy -- , sort -- , sortBy + , Pattern(..) + , stripPrefix , slice , take , takeWhile @@ -96,21 +98,20 @@ import Prelude import Control.Alt ((<|>)) import Control.Alternative (class Alternative) import Control.Lazy as Z - +import Control.Monad.Rec.Class as Rec import Data.Foldable (class Foldable, foldr, any, foldl) +import Data.Foldable (foldl, foldr, foldMap, fold, intercalate, elem, notElem, find, findMap, any, all) as Exports import Data.Lazy (defer) import Data.List.Lazy.Types (List(..), Step(..), step, nil, cons, (:)) import Data.List.Lazy.Types (NonEmptyList(..)) as NEL import Data.Maybe (Maybe(..), isNothing) -import Data.Newtype (unwrap) +import Data.Newtype (class Newtype, unwrap) import Data.NonEmpty ((:|)) +import Data.Traversable (scanl, scanr) as Exports import Data.Traversable (sequence) import Data.Tuple (Tuple(..)) import Data.Unfoldable (class Unfoldable, unfoldr) -import Data.Foldable (foldl, foldr, foldMap, fold, intercalate, elem, notElem, find, findMap, any, all) as Exports -import Data.Traversable (scanl, scanr) as Exports - -- | Convert a list into any unfoldable structure. -- | -- | Running time: `O(n)` @@ -472,6 +473,34 @@ catMaybes = mapMaybe id -- Sublists -------------------------------------------------------------------- -------------------------------------------------------------------------------- + +-- | A newtype used in cases where there is a list to be matched. +newtype Pattern a = Pattern (List a) + +derive instance eqPattern :: Eq a => Eq (Pattern a) +derive instance ordPattern :: Ord a => Ord (Pattern a) +derive instance newtypePattern :: Newtype (Pattern a) _ + +instance showPattern :: Show a => Show (Pattern a) where + show (Pattern s) = "(Pattern " <> show s <> ")" + + +-- | If the list starts with the given prefix, return the portion of the +-- | list left after removing it, as a Just value. Otherwise, return Nothing. +-- | * `stripPrefix (Pattern (fromFoldable [1])) (fromFoldable [1,2]) == Just (fromFoldable [2])` +-- | * `stripPrefix (Pattern (fromFoldable [])) (fromFoldable [1]) == Just (fromFoldable [1])` +-- | * `stripPrefix (Pattern (fromFoldable [2])) (fromFoldable [1]) == Nothing` +-- | +-- | Running time: `O(n)` where `n` is the number of elements to strip. +stripPrefix :: forall a. Eq a => Pattern a -> List a -> Maybe (List a) +stripPrefix (Pattern p') s = Rec.tailRecM2 go p' s + where + go prefix input = case step prefix of + Nil -> Just $ Rec.Done input + Cons p ps -> case step input of + Cons i is | p == i -> Just $ Rec.Loop { a: ps, b: is } + _ -> Nothing + -- | Extract a sublist by a start and end index. slice :: Int -> Int -> List ~> List slice start end xs = take (end - start) (drop start xs) diff --git a/test/Test/Data/List/Lazy.purs b/test/Test/Data/List/Lazy.purs index d29ea11..b66e5ec 100644 --- a/test/Test/Data/List/Lazy.purs +++ b/test/Test/Data/List/Lazy.purs @@ -7,7 +7,7 @@ import Control.Monad.Eff (Eff) import Control.Monad.Eff.Console (CONSOLE, log) import Data.Lazy as Z -import Data.List.Lazy (List, nil, cons, foldl, foldr, foldMap, singleton, transpose, take, iterate, filter, uncons, foldM, foldrLazy, range, unzip, zip, length, zipWithA, replicate, repeat, zipWith, intersectBy, intersect, deleteBy, delete, unionBy, union, nubBy, nub, groupBy, group, partition, span, dropWhile, drop, takeWhile, slice, catMaybes, mapMaybe, filterM, concat, concatMap, reverse, alterAt, modifyAt, updateAt, deleteAt, insertAt, findLastIndex, findIndex, elemLastIndex, elemIndex, init, tail, last, head, insertBy, insert, snoc, null, replicateM, fromFoldable, (:), (\\), (!!)) +import Data.List.Lazy (List, nil, stripPrefix, Pattern(..), cons, foldl, foldr, foldMap, singleton, transpose, take, iterate, filter, uncons, foldM, foldrLazy, range, unzip, zip, length, zipWithA, replicate, repeat, zipWith, intersectBy, intersect, deleteBy, delete, unionBy, union, nubBy, nub, groupBy, group, partition, span, dropWhile, drop, takeWhile, slice, catMaybes, mapMaybe, filterM, concat, concatMap, reverse, alterAt, modifyAt, updateAt, deleteAt, insertAt, findLastIndex, findIndex, elemLastIndex, elemIndex, init, tail, last, head, insertBy, insert, snoc, null, replicateM, fromFoldable, (:), (\\), (!!)) import Data.List.Lazy.NonEmpty as NEL import Data.Maybe (Maybe(..), isNothing, fromJust) import Data.Monoid.Additive (Additive(..)) @@ -25,6 +25,10 @@ testListLazy = do l = fromFoldable nel xxs = NEL.NonEmptyList (Z.defer \_ -> xxs) longList = range 1 100000 + log "strip prefix" + assert $ stripPrefix (Pattern (l [1])) (l [1,2]) == Just (l [2]) + assert $ stripPrefix (Pattern (l [])) (l [1]) == Just (l [1]) + assert $ stripPrefix (Pattern (l [2])) (l [1]) == Nothing log "append should be stack-safe" assert $ length (longList <> longList) == (2 * length longList)