diff --git a/CHANGES b/CHANGES
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,11 @@
+* 0.2.5 (9 January 2024)
+
+  - Test with GHC 9.8.
+  - New function `mapSplitter` witnessing the fact that `Splitter` is
+    a contravariant functor
+    ([#22](https://github.com/byorgey/split/pull/22), thanks to Ellis
+    Kesterton)
+
 * 0.2.4 (9 October 2023)
 
   - Test with GHC 9.6.
diff --git a/split.cabal b/split.cabal
--- a/split.cabal
+++ b/split.cabal
@@ -1,5 +1,5 @@
 Name:                split
-Version:             0.2.4
+Version:             0.2.5
 Stability:           stable
 
 Description:         A collection of various methods for splitting
@@ -35,7 +35,7 @@
 Category:            List
 Build-type:          Simple
 Cabal-Version:       >= 1.10
-Tested-with:         GHC ==9.6.2 || ==9.4.5 || ==9.2.7 || ==9.0.2 || ==8.10.7 || ==8.8.4 || ==8.6.5 || ==8.4.4 || ==8.2.2 || ==8.0.2 || ==7.10.3 || ==7.8.4 || ==7.6.3 || ==7.4.2 || ==7.2.2 || ==7.0.4
+Tested-with:         GHC ==9.8.1 || ==9.6.3 || ==9.4.8 || ==9.2.8 || ==9.0.2 || ==8.10.7 || ==8.8.4 || ==8.6.5 || ==8.4.4 || ==8.2.2 || ==8.0.2 || ==7.10.3 || ==7.8.4 || ==7.6.3 || ==7.4.2 || ==7.2.2 || ==7.0.4
 
 Bug-reports:         https://github.com/byorgey/split/issues
 
diff --git a/src/Data/List/Split.hs b/src/Data/List/Split.hs
--- a/src/Data/List/Split.hs
+++ b/src/Data/List/Split.hs
@@ -61,6 +61,7 @@
   dropInitBlank,
   dropFinalBlank,
   dropInnerBlanks,
+  mapSplitter,
 
   -- ** Derived combinators
   -- $derived
diff --git a/src/Data/List/Split/Internals.hs b/src/Data/List/Split/Internals.hs
--- a/src/Data/List/Split/Internals.hs
+++ b/src/Data/List/Split/Internals.hs
@@ -379,6 +379,20 @@
 dropInnerBlanks :: Splitter a -> Splitter a
 dropInnerBlanks s = s {condensePolicy = DropBlankFields}
 
+-- | Split over a different type of element by performing a preprocessing step.
+--
+-- >>> split (mapSplitter snd $ oneOf "-_") $ zip [0..] "a-bc_d"
+-- [[(0,'a')],[(1,'-')],[(2,'b'),(3,'c')],[(4,'_')],[(5,'d')]]
+--
+-- >>> import Data.Char (toLower)
+-- >>> split (mapSplitter toLower $ dropDelims $ whenElt (== 'x')) "abXcxd"
+-- ["ab","c","d"]
+mapSplitter :: (b -> a) -> Splitter a -> Splitter b
+mapSplitter f (Splitter d dp cp ibp fbp) = Splitter (mapDelimiter f d) dp cp ibp fbp
+ where
+  mapDelimiter :: (b -> a) -> Delimiter a -> Delimiter b
+  mapDelimiter g (Delimiter xs) = Delimiter $ map (. g) xs
+
 -- ** Derived combinators
 
 -- | Drop all blank chunks from the output, and condense consecutive
