on master help sign in
Support deconstruction for view patterns

--HG-- extra : convert_revision : e9f4a94c165dcc902990378bb49e2ae412164e6d

commit17950c9ed13ae2c29910387d3028af71768106cd authorBryan O'Sullivan <bos@serpentine.com> dateFri 13 Aug 2010, 22:24 (16 years ago) parent12df873
3 files changed+126−2
Data/Text.hs+52−1 Data/Text/Lazy.hs+53 tests/Properties.hs+21−1
Data/Text.hs+52−1
@@ -140,6 +140,10 @@ module Data.Text
140140 , isSuffixOf
141141 , isInfixOf
142142
143+ -- ** View patterns
144+ , prefixed
145+ , suffixed
146+
143147 -- * Searching
144148 , filter
145149 , find
@@ -165,7 +169,7 @@ module Data.Text
165169import Prelude (Char, Bool(..), Functor(..), Int, Maybe(..), String,
166170 Eq(..), Ord(..), (++),
167171 Read(..), Show(..),
168− (&&), (||), (+), (-), (.), ($), (>>), (*),
172+ (&&), (||), (+), (-), (.), ($), ($!), (>>), (*),
169173 div, error, not, return, otherwise)
170174#if defined(HAVE_DEEPSEQ)
171175import Control.DeepSeq (NFData)
@@ -1289,5 +1293,52 @@ isInfixOf needle haystack
12891293 isInfixOf (singleton n) h = S.elem n (S.stream h)
12901294 #-}
12911295
1296+-------------------------------------------------------------------------------
1297+-- * View patterns
1298+
1299+-- | /O(n)/ Returns the suffix of the second string if its prefix
1300+-- matches the first.
1301+--
1302+-- Examples:
1303+--
1304+-- > prefixed "foo" "foobar" == Just "bar"
1305+-- > prefixed "foo" "quux" == Nothing
1306+--
1307+-- This is particularly useful with the @ViewPatterns@ extension to
1308+-- GHC, as follows:
1309+--
1310+-- > {-# LANGUAGE ViewPatterns #-}
1311+-- > import Data.Text as T
1312+-- >
1313+-- > fnordLength :: Text -> Int
1314+-- > fnordLength (prefixed "fnord" -> Just suf) = T.length suf
1315+-- > fnordLength _ = -1
1316+prefixed :: Text -> Text -> Maybe Text
1317+prefixed p@(Text _arr _off plen) t@(Text arr off len)
1318+ | p `isPrefixOf` t = Just $! textP arr (off+plen) (len-plen)
1319+ | otherwise = Nothing
1320+
1321+-- | /O(n)/ Returns the prefix of the second string if its suffix
1322+-- matches the first.
1323+--
1324+-- Examples:
1325+--
1326+-- > suffixed "bar" "foobar" == Just "foo"
1327+-- > suffixed "foo" "quux" == Nothing
1328+--
1329+-- This is particularly useful with the @ViewPatterns@ extension to
1330+-- GHC, as follows:
1331+--
1332+-- > {-# LANGUAGE ViewPatterns #-}
1333+-- > import Data.Text as T
1334+-- >
1335+-- > quuxLength :: Text -> Int
1336+-- > quuxLength (suffixed "quux" -> Just pre) = T.length pre
1337+-- > quuxLength _ = -1
1338+suffixed :: Text -> Text -> Maybe Text
1339+suffixed p@(Text _arr _off plen) t@(Text arr off len)
1340+ | p `isSuffixOf` t = Just $! textP arr off (len-plen)
1341+ | otherwise = Nothing
1342+
12921343emptyError :: String -> a
12931344emptyError fun = P.error ("Data.Text." ++ fun ++ ": empty input")
Data/Text/Lazy.hs+53
@@ -144,6 +144,10 @@ module Data.Text.Lazy
144144 , isSuffixOf
145145 , isInfixOf
146146
147+ -- ** View patterns
148+ , prefixed
149+ , suffixed
150+
147151 -- * Searching
148152 , filter
149153 , find
@@ -1156,6 +1160,55 @@ isInfixOf needle haystack
11561160 isInfixOf (singleton n) h = S.elem n (S.stream h)
11571161 #-}
11581162
1163+-------------------------------------------------------------------------------
1164+-- * View patterns
1165+
1166+-- | /O(n)/ Returns the suffix of the second string if its prefix
1167+-- matches the first.
1168+--
1169+-- Examples:
1170+--
1171+-- > prefixed "foo" "foobar" == Just "bar"
1172+-- > prefixed "foo" "quux" == Nothing
1173+--
1174+-- This is particularly useful with the @ViewPatterns@ extension to
1175+-- GHC, as follows:
1176+--
1177+-- > {-# LANGUAGE ViewPatterns #-}
1178+-- > import Data.Text as T
1179+-- >
1180+-- > fnordLength :: Text -> Int
1181+-- > fnordLength (prefixed "fnord" -> Just suf) = T.length suf
1182+-- > fnordLength _ = -1
1183+prefixed :: Text -> Text -> Maybe Text
1184+-- Yes, this could be much more efficient.
1185+prefixed p t
1186+ | p `isPrefixOf` t = Just (drop (length p) t)
1187+ | otherwise = Nothing
1188+
1189+-- | /O(n)/ Returns the prefix of the second string if its suffix
1190+-- matches the first.
1191+--
1192+-- Examples:
1193+--
1194+-- > suffixed "bar" "foobar" == Just "foo"
1195+-- > suffixed "foo" "quux" == Nothing
1196+--
1197+-- This is particularly useful with the @ViewPatterns@ extension to
1198+-- GHC, as follows:
1199+--
1200+-- > {-# LANGUAGE ViewPatterns #-}
1201+-- > import Data.Text as T
1202+-- >
1203+-- > quuxLength :: Text -> Int
1204+-- > quuxLength (suffixed "quux" -> Just pre) = T.length pre
1205+-- > quuxLength _ = -1
1206+suffixed :: Text -> Text -> Maybe Text
1207+-- Yes, this could be much more efficient.
1208+suffixed p t
1209+ | p `isSuffixOf` t = Just (take (length t - length p) t)
1210+ | otherwise = Nothing
1211+
11591212-- | /O(n)/ 'filter', applied to a predicate and a 'Text',
11601213-- returns a 'Text' containing those characters that satisfy the
11611214-- predicate.
tests/Properties.hs+21−1
@@ -496,6 +496,19 @@ tl_isSuffixOf s = L.isSuffixOf s`eqP` TL.isSuffixOf (packS s)
496496t_isInfixOf s = L.isInfixOf s `eqP` T.isInfixOf (packS s)
497497tl_isInfixOf s = L.isInfixOf s `eqP` TL.isInfixOf (packS s)
498498
499+prefixed (p:ps) (t:ts)
500+ | p == t = prefixed ps ts
501+prefixed [] ts = Just ts
502+prefixed _ _ = Nothing
503+
504+t_prefixed s = (fmap packS . prefixed s) `eqP` T.prefixed (packS s)
505+tl_prefixed s = (fmap packS . prefixed s) `eqP` TL.prefixed (packS s)
506+
507+suffixed p t = reverse `fmap` prefixed (reverse p) (reverse t)
508+
509+t_suffixed s = (fmap packS . suffixed s) `eqP` T.suffixed (packS s)
510+tl_suffixed s = (fmap packS . suffixed s) `eqP` TL.suffixed (packS s)
511+
499512sf_elem p c = (L.elem c . L.filter p) `eqP` (S.elem c . S.filter p)
500513sf_filter q p = (L.filter p . L.filter q) `eqP` (unpackS . S.filter p . S.filter q)
501514t_filter p = L.filter p `eqP` (unpackS . T.filter p)
@@ -871,7 +884,14 @@ tests = [
871884 testProperty "t_isSuffixOf" t_isSuffixOf,
872885 testProperty "tl_isSuffixOf" tl_isSuffixOf,
873886 testProperty "t_isInfixOf" t_isInfixOf,
874− testProperty "tl_isInfixOf" tl_isInfixOf
887+ testProperty "tl_isInfixOf" tl_isInfixOf,
888+
889+ testGroup "view" [
890+ testProperty "t_prefixed" t_prefixed,
891+ testProperty "tl_prefixed" tl_prefixed,
892+ testProperty "t_suffixed" t_suffixed,
893+ testProperty "tl_suffixed" tl_suffixed
894+ ]
875895 ],
876896
877897 testGroup "searching" [