mono-traversable 1.0.0.1 → 1.0.1
raw patch · 5 files changed
+72/−3 lines, 5 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Data.MonoTraversable: replaceElem :: (MonoFunctor mono, Eq (Element mono)) => Element mono -> Element mono -> mono -> mono
+ Data.MonoTraversable: replaceElemLazyText :: Char -> Char -> Text -> Text
+ Data.MonoTraversable: replaceElemStrictText :: Char -> Char -> Text -> Text
+ Data.Sequences: replaceSeq :: (IsSequence seq, Eq (Element seq)) => seq -> seq -> seq -> seq
+ Data.Sequences: replaceSeqLazyText :: Text -> Text -> Text -> Text
+ Data.Sequences: replaceSeqStrictText :: Text -> Text -> Text -> Text
Files
- ChangeLog.md +4/−0
- mono-traversable.cabal +1/−1
- src/Data/MonoTraversable.hs +16/−1
- src/Data/Sequences.hs +24/−1
- test/Spec.hs +27/−0
ChangeLog.md view
@@ -1,3 +1,7 @@+## 1.0.1++* Add `replaceElem` and `replaceSeq` [#107](https://github.com/snoyberg/mono-traversable/pull/107)+ ## 1.0.0.1 * Add missing export [#101](https://github.com/snoyberg/mono-traversable/pull/101)
mono-traversable.cabal view
@@ -1,5 +1,5 @@ name: mono-traversable-version: 1.0.0.1+version: 1.0.1 synopsis: Type classes for mapping, folding, and traversing monomorphic containers description: Monomorphic variants of the Functor, Foldable, and Traversable typeclasses. If you understand Haskell's basic typeclasses, you understand mono-traversable. In addition to what you are used to, it adds on an IsSequence typeclass and has code for marking data structures as non-empty. homepage: https://github.com/snoyberg/mono-traversable
src/Data/MonoTraversable.hs view
@@ -45,7 +45,7 @@ import GHC.Exts (build) import Prelude (Bool (..), const, Char, flip, IO, Maybe (..), Either (..), (+), Integral, Ordering (..), compare, fromIntegral, Num, (>=),- seq, otherwise, Eq, Ord, (-), (*))+ (==), seq, otherwise, Eq, Ord, (-), (*)) import qualified Prelude import qualified Data.ByteString.Internal as Unsafe import qualified Foreign.ForeignPtr.Unsafe as Unsafe@@ -198,6 +198,21 @@ instance VS.Storable a => MonoFunctor (VS.Vector a) where omap = VS.map {-# INLINE omap #-}++-- | @'replaceElem' old new@ replaces all @old@ elements with @new@.+--+-- @since 1.0.1+replaceElem :: (MonoFunctor mono, Eq (Element mono)) => Element mono -> Element mono -> mono -> mono+replaceElem old new = omap (\x -> if x == old then new else x)++{-# INLINE [0] replaceElem #-}+{-# RULES "strict Text replaceElem" replaceElem = replaceElemStrictText #-}+replaceElemStrictText :: Char -> Char -> T.Text -> T.Text+replaceElemStrictText old new = T.replace (T.singleton old) (T.singleton new)+{-# RULES "lazy Text replaceElem" replaceElem = replaceElemLazyText #-}+replaceElemLazyText :: Char -> Char -> TL.Text -> TL.Text+replaceElemLazyText old new = TL.replace (TL.singleton old) (TL.singleton new)+ -- | Monomorphic containers that can be folded. class MonoFoldable mono where
src/Data/Sequences.hs view
@@ -1169,7 +1169,7 @@ -- | @'splitSeq'@ splits a sequence into components delimited by -- separator subsequence. 'splitSeq' is the right inverse of 'intercalate': ----- > intercalate x . splitSeq x === id+-- > ointercalate x . splitSeq x === id -- -- 'splitElem' can be considered a special case of 'splitSeq' --@@ -1192,6 +1192,15 @@ splitSeq :: (IsSequence seq, Eq (Element seq)) => seq -> seq -> [seq] splitSeq sep = List.map fromList . List.splitOn (otoList sep) . otoList +-- | @'replaceSeq' old new@ replaces all @old@ subsequences with @new@.+--+-- > replaceSeq old new === ointercalate new . splitSeq old+--+-- @since 1.0.1++replaceSeq :: (IsSequence seq, Eq (Element seq)) => seq -> seq -> seq -> seq+replaceSeq old new = ointercalate new . splitSeq old+ -- | 'stripPrefix' drops the given prefix from a sequence. -- It returns 'Nothing' if the sequence did not start with the prefix -- given, or 'Just' the sequence after the prefix, if it does.@@ -1259,8 +1268,10 @@ -- @since 0.10.2 deleteBy :: (IsSequence seq, Eq (Element seq)) => (Element seq -> Element seq -> Bool) -> Element seq -> seq -> seq deleteBy eq x = fromList . List.deleteBy eq x . otoList+ {-# INLINE [0] splitElem #-} {-# INLINE [0] splitSeq #-}+{-# INLINE [0] replaceSeq #-} {-# INLINE [0] isPrefixOf #-} {-# INLINE [0] isSuffixOf #-} {-# INLINE [0] isInfixOf #-}@@ -1325,6 +1336,7 @@ | otherwise = Nothing {-# RULES "strict Text splitSeq" splitSeq = splitSeqStrictText #-}+{-# RULES "strict Text replaceSeq" replaceSeq = replaceSeqStrictText #-} {-# RULES "strict Text stripPrefix" stripPrefix = T.stripPrefix #-} {-# RULES "strict Text stripSuffix" stripSuffix = T.stripSuffix #-} {-# RULES "strict Text group" group = T.group #-}@@ -1337,7 +1349,13 @@ | T.null sep = (:) T.empty . List.map singleton . T.unpack | otherwise = T.splitOn sep +replaceSeqStrictText :: T.Text -> T.Text -> T.Text -> T.Text+replaceSeqStrictText old new+ | T.null old = T.intercalate new . splitSeqStrictText old+ | otherwise = T.replace old new+ {-# RULES "lazy Text splitSeq" splitSeq = splitSeqLazyText #-}+{-# RULES "lazy Text replaceSeq" replaceSeq = replaceSeqLazyText #-} {-# RULES "lazy Text stripPrefix" stripPrefix = TL.stripPrefix #-} {-# RULES "lazy Text stripSuffix" stripSuffix = TL.stripSuffix #-} {-# RULES "lazy Text group" group = TL.group #-}@@ -1349,6 +1367,11 @@ splitSeqLazyText sep | TL.null sep = (:) TL.empty . List.map singleton . TL.unpack | otherwise = TL.splitOn sep++replaceSeqLazyText :: TL.Text -> TL.Text -> TL.Text -> TL.Text+replaceSeqLazyText old new+ | TL.null old = TL.intercalate new . splitSeqLazyText old+ | otherwise = TL.replace old new -- | Sort a ordered sequence. --
test/Spec.hs view
@@ -2,6 +2,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE CPP #-} module Spec where @@ -373,6 +374,32 @@ let x1 = Foldl.fold Foldl.length (xs :: [Int]) x2 = Foldl.purely ofoldlUnwrap Foldl.length xs x2 @?= x1++ describe "Replacing" $ do+ let test typ dummy = describe typ $ do+ prop "replaceElem old new === omap (\\x -> if x == old then new else x)" $+ -- replace random element or any random value with random new value+ \x list new -> forAll (elements (x:list)) $ \old ->+ let seq' = fromListAs list dummy+ in replaceElem old new seq' @?= omap (\x -> if x == old then new else x) seq'+#if MIN_VERSION_QuickCheck(2,8,0)+ prop "replaceSeq old new === ointercalate new . splitSeq old" $+ -- replace random subsequence with random new sequence+ \list new -> forAll (sublistOf list) $ \old ->+ let [seq', old', new'] = map (`fromListAs` dummy) [list, old, new]+ in replaceSeq old' new' seq' @?= ointercalate new' (splitSeq old' seq')+ prop "replaceSeq old old === id" $ \list -> forAll (sublistOf list) $ \old ->+ let [seq', old'] = map (`fromListAs` dummy) [list, old]+ in replaceSeq old' old' seq' @?= seq'+#endif+ test "List" ([] :: [Int])+ test "Vector" (V.empty :: V.Vector Int)+ test "Storable Vector" (VS.empty :: VS.Vector Int)+ test "Unboxed Vector" (U.empty :: U.Vector Int)+ test "Strict ByteString" S.empty+ test "Lazy ByteString" L.empty+ test "Strict Text" T.empty+ test "Lazy Text" TL.empty describe "Sorting" $ do let test typ dummy = describe typ $ do