diff --git a/ascii-superset.cabal b/ascii-superset.cabal
--- a/ascii-superset.cabal
+++ b/ascii-superset.cabal
@@ -1,7 +1,7 @@
 cabal-version: 3.0
 
 name: ascii-superset
-version: 1.1.1.0
+version: 1.2.0.0
 synopsis: Representing ASCII with refined supersets
 category: Data, Text
 
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,31 @@
+### 1.2.0.0 (2023-01-03)
+
+Add to the `CharSuperset` class a new method:
+
+```haskell
+toCaseChar :: Case -> char -> char
+```
+
+Add to the `StringSuperset` class a new method:
+
+```haskell
+toCaseString :: Case -> string -> string
+```
+
+Add to the `ASCII.CaseRefinement` module:
+
+```haskell
+refineCharToCase :: forall letterCase char.
+    KnownCase letterCase => CharSuperset char =>
+    ASCII char -> ASCII'case letterCase char
+```
+
+```haskell
+refineStringToCase :: forall letterCase char.
+    KnownCase letterCase => StringSuperset char =>
+    ASCII char -> ASCII'case letterCase char
+```
+
 ### 1.1.1.0 (2023-01-03)
 
 Add to `ASCII.CaseRefinement` the `KnownCase` class.
diff --git a/library/ASCII/CaseRefinement.hs b/library/ASCII/CaseRefinement.hs
--- a/library/ASCII/CaseRefinement.hs
+++ b/library/ASCII/CaseRefinement.hs
@@ -3,21 +3,23 @@
     {- * ASCII'case type constructor -} ASCII'case, lift, asciiCaseUnsafe,
     {- ** Aliases -} {- $aliases -} ASCII'upper, ASCII'lower,
     {- * Character functions -} validateChar, fromCaselessChar,
-          toCaselessChar, substituteChar, asCaselessChar,
+          toCaselessChar, substituteChar, asCaselessChar, refineCharToCase,
     {- * String functions -} validateString, fromCaselessCharList,
-          toCaselessCharList, substituteString, mapChars,
+          toCaselessCharList, substituteString, mapChars, refineStringToCase,
     {- * KnownCase -} KnownCase (..),
   )
   where
 
 import ASCII.Case (Case (..))
 import ASCII.Caseless (CaselessChar)
+import {-# source #-} ASCII.Refinement (ASCII)
 import ASCII.Superset (CharSuperset, StringSuperset)
 
 import qualified ASCII.Case as Case
 import qualified ASCII.Caseless as Caseless
 import qualified ASCII.Char as ASCII
 import qualified ASCII.Superset as Superset
+import {-# source #-} qualified ASCII.Refinement as Refinement
 
 import Control.Monad (guard)
 import Data.Bool (Bool (..))
@@ -145,7 +147,7 @@
     ASCII'case letterCase superset {- ^ Character that is known to be ASCII, and
                                         in the particular case if it is a letter -}
     -> CaselessChar
-toCaselessChar =  Caseless.disregardCase . Superset.toCharUnsafe . lift
+toCaselessChar = Caseless.disregardCase . Superset.toCharUnsafe . lift
 
 {-| Given a character from a larger set that is known to represent an ASCII
 character, manipulate it as if it were an ASCII character -}
@@ -158,6 +160,12 @@
   where
     g = Caseless.toCase (theCase @letterCase) . f . Caseless.assumeCaseUnsafe (theCase @letterCase)
 
+{-| Given an ASCII superset character that is known to be valid ASCII,
+refine it further by converting it to a particular letter case -}
+refineCharToCase :: forall letterCase char. KnownCase letterCase => CharSuperset char =>
+    ASCII char -> ASCII'case letterCase char
+refineCharToCase = asciiCaseUnsafe . Superset.toCaseChar (theCase @letterCase) . Refinement.lift
+
 ---
 
 {-| Return 'Just' an 'ASCII'case' string if the input consists entirely of ASCII
@@ -206,3 +214,9 @@
 mapChars f = asciiCaseUnsafe . Superset.mapCharsUnsafe g . lift
   where
     g = Caseless.toCase (theCase @letterCase) . f . Caseless.assumeCaseUnsafe (theCase @letterCase)
+
+{-| Given an ASCII superset string that is known to be valid ASCII,
+refine it further by converting it to a particular letter case -}
+refineStringToCase :: forall letterCase char. KnownCase letterCase => StringSuperset char =>
+    ASCII char -> ASCII'case letterCase char
+refineStringToCase = asciiCaseUnsafe . Superset.toCaseString (theCase @letterCase) . Refinement.lift
diff --git a/library/ASCII/Refinement.hs b/library/ASCII/Refinement.hs
--- a/library/ASCII/Refinement.hs
+++ b/library/ASCII/Refinement.hs
@@ -10,6 +10,7 @@
 import qualified ASCII.Isomorphism as I
 import qualified ASCII.Superset as S
 
+import ASCII.CaseRefinement (KnownCase (..), ASCII'case, ASCII'upper, ASCII'lower)
 import Data.Data (Data)
 import Data.Eq (Eq)
 import Data.Function (id, ($), (.))
@@ -66,7 +67,8 @@
 instance S.CharSuperset char => S.FromChar (ASCII char) where
     fromChar = asciiUnsafe . S.fromChar
 
-instance S.CharSuperset char => S.CharSuperset (ASCII char)
+instance S.CharSuperset char => S.CharSuperset (ASCII char) where
+    toCaseChar c = asciiUnsafe . S.toCaseChar c . lift
 
 instance S.CharSuperset char => I.CharIso (ASCII char) where
     toChar = S.toCharUnsafe
@@ -86,6 +88,7 @@
 
 instance S.StringSuperset string => S.StringSuperset (ASCII string) where
     substituteString = id
+    toCaseString c = asciiUnsafe . S.toCaseString c . lift
 
 instance S.StringSuperset string => I.StringIso (ASCII string) where
     toCharList = S.toCharListUnsafe
diff --git a/library/ASCII/Refinement.hs-boot b/library/ASCII/Refinement.hs-boot
new file mode 100644
--- /dev/null
+++ b/library/ASCII/Refinement.hs-boot
@@ -0,0 +1,5 @@
+module ASCII.Refinement where
+
+data ASCII superset
+
+lift :: ASCII superset -> superset
diff --git a/library/ASCII/Superset.hs b/library/ASCII/Superset.hs
--- a/library/ASCII/Superset.hs
+++ b/library/ASCII/Superset.hs
@@ -1,7 +1,7 @@
 module ASCII.Superset
   (
     {- * Characters -}
-    {- ** Class -} ToCaselessChar (..), ToChar (..), FromChar (..), CharSuperset,
+    {- ** Class -} ToCaselessChar (..), ToChar (..), FromChar (..), CharSuperset (..),
     {- ** Functions -} asCharUnsafe, toCharMaybe, toCaselessCharMaybe, toCharOrFail, toCaselessCharOrFail,
         toCharSub, toCaselessCharSub, substituteChar, convertCharMaybe, convertCharOrFail,
 
@@ -12,6 +12,7 @@
   )
   where
 
+import ASCII.Case (Case (..))
 import ASCII.Caseless (CaselessChar)
 import Control.Monad (return)
 import Control.Monad.Fail (MonadFail (fail))
@@ -20,7 +21,9 @@
 import Data.Functor (fmap)
 import Data.Maybe (Maybe (..))
 import Data.Ord ((<=), (>=))
+import Prelude ((+), (-))
 
+import qualified ASCII.Case as Case
 import qualified ASCII.Caseless as Caseless
 import qualified ASCII.Char as ASCII
 import qualified Data.Bool as Bool
@@ -82,8 +85,13 @@
 
 - a total conversion from ASCII; and
 - a partial conversion to ASCII -}
-class (ToChar char, FromChar char) => CharSuperset char
+class (ToChar char, FromChar char) => CharSuperset char where
 
+    {- | Convert a character in the superset to the designated case,
+    if it is an ASCII letter of the opposite case. Otherwise, return
+    the argument unmodified. -}
+    toCaseChar :: Case -> char -> char
+
 {-| Manipulate a character as if it were an ASCII 'ASCII.Char', assuming that it is
 
 Defined only where 'isAsciiChar' is satisfied. -}
@@ -194,6 +202,10 @@
     mapCharsUnsafe :: (ASCII.Char -> ASCII.Char) -> string -> string
     mapCharsUnsafe f = fromCharList  . List.map f . toCharListUnsafe
 
+    {- | Convert each character in the superset to the designated case, if it is
+    an ASCII letter of the opposite case. Leaves other characters unchanged. -}
+    toCaseString :: Case -> string -> string
+
 toCharListMaybe :: ToString string => string -> Maybe [ASCII.Char]
 toCharListMaybe = toCharListOrFail
 
@@ -229,7 +241,7 @@
 
 ---  Instances  ---
 
--- | 'CaselessChar' is trivially convertible to itself. (This instance is uninteresting.)
+-- | 'CaselessChar' is trivially convertible to itself.
 instance ToCaselessChar CaselessChar where
     isAsciiCaselessChar _ = Bool.True
     toCaselessCharUnsafe = id
@@ -247,8 +259,9 @@
 instance FromChar ASCII.Char where
     fromChar = id
 
--- | 'ASCII.Char' is trivially a superset of itself. (This instance is uninteresting.)
-instance CharSuperset ASCII.Char
+-- | 'ASCII.Char' is trivially a superset of itself.
+instance CharSuperset ASCII.Char where
+    toCaseChar = Case.toCase
 
 ---
 
@@ -263,7 +276,10 @@
 instance FromChar Unicode.Char where
     fromChar = Unicode.chr . ASCII.toInt
 
-instance CharSuperset Unicode.Char
+instance CharSuperset Unicode.Char where
+    toCaseChar UpperCase x | x >= 'a' && x <= 'z' = Unicode.chr (Unicode.ord x - 32)
+    toCaseChar LowerCase x | x >= 'A' && x <= 'Z' = Unicode.chr (Unicode.ord x + 32)
+    toCaseChar _ x = x
 
 ---
 
@@ -278,7 +294,10 @@
 instance FromChar Nat.Natural where
     fromChar = Prelude.fromIntegral . ASCII.toInt
 
-instance CharSuperset Nat.Natural
+instance CharSuperset Nat.Natural where
+    toCaseChar UpperCase x | x >= 97 && x <= 122 = x - 32
+    toCaseChar LowerCase x | x >= 65 && x <= 90  = x + 32
+    toCaseChar _ x = x
 
 ---
 
@@ -293,7 +312,10 @@
 instance FromChar Int.Int where
     fromChar = ASCII.toInt
 
-instance CharSuperset Int.Int
+instance CharSuperset Int.Int where
+    toCaseChar UpperCase x | x >= 97 && x <= 122 = x - 32
+    toCaseChar LowerCase x | x >= 65 && x <= 90  = x + 32
+    toCaseChar _ x = x
 
 ---
 
@@ -308,7 +330,10 @@
 instance FromChar Word.Word8 where
     fromChar = Prelude.fromIntegral . ASCII.toInt
 
-instance CharSuperset Word.Word8
+instance CharSuperset Word.Word8 where
+    toCaseChar UpperCase x | x >= 97 && x <= 122 = x - 32
+    toCaseChar LowerCase x | x >= 65 && x <= 90  = x + 32
+    toCaseChar _ x = x
 
 ---
 
@@ -327,6 +352,7 @@
 
 instance CharSuperset char => StringSuperset [char] where
     substituteString = List.map substituteChar
+    toCaseString c = List.map (toCaseChar c)
 
 ---
 
@@ -346,6 +372,7 @@
 instance StringSuperset T.Text where
     substituteString = T.map substituteChar
     mapCharsUnsafe f = T.map (asCharUnsafe f)
+    toCaseString c   = T.map (toCaseChar c)
 
 ---
 
@@ -365,6 +392,7 @@
 instance StringSuperset LT.Text where
     substituteString = LT.map substituteChar
     mapCharsUnsafe f = LT.map (asCharUnsafe f)
+    toCaseString c   = LT.map (toCaseChar c)
 
 ---
 
@@ -384,6 +412,7 @@
 instance StringSuperset TB.Builder where
     substituteString = TB.fromLazyText . substituteString . TB.toLazyText
     mapCharsUnsafe f = TB.fromLazyText . mapCharsUnsafe f . TB.toLazyText
+    toCaseString c   = TB.fromLazyText . toCaseString c   . TB.toLazyText
 
 ---
 
@@ -403,6 +432,7 @@
 instance StringSuperset BS.ByteString where
     substituteString = BS.map substituteChar
     mapCharsUnsafe f = BS.map (asCharUnsafe f)
+    toCaseString c   = BS.map (toCaseChar c)
 
 ---
 
@@ -422,6 +452,7 @@
 instance StringSuperset LBS.ByteString where
     substituteString = LBS.map substituteChar
     mapCharsUnsafe f = LBS.map (asCharUnsafe f)
+    toCaseString c   = LBS.map (toCaseChar c)
 
 ---
 
@@ -441,3 +472,4 @@
 instance StringSuperset BSB.Builder where
     substituteString = BSB.lazyByteString . substituteString . BSB.toLazyByteString
     mapCharsUnsafe f = BSB.lazyByteString . mapCharsUnsafe f . BSB.toLazyByteString
+    toCaseString c   = BSB.lazyByteString . toCaseString c   . BSB.toLazyByteString
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -2,20 +2,29 @@
 
 import Test.Hspec
 
-import ASCII.Refinement (ASCII, asciiUnsafe)
+import ASCII.Case (Case (..))
 import ASCII.CaseRefinement (ASCII'lower, ASCII'upper, asciiCaseUnsafe)
+import ASCII.Char (Char (..))
+import ASCII.Refinement (ASCII, asciiUnsafe)
 
+import qualified ASCII.Case as Case
+import qualified ASCII.Caseless as CC
 import qualified ASCII.CaseRefinement as CaseRefinement
+import qualified ASCII.Char as ASCII
 import qualified ASCII.Lift as Lift
 import qualified ASCII.Refinement as Refinement
+import qualified ASCII.Superset as Superset
 
-import ASCII.Char (Char (..))
-import qualified ASCII.Caseless as CC
+import qualified Data.Foldable as Foldable
 
+import Data.Function ((&))
 import Data.Text (Text)
 import Data.Word (Word8)
+import Numeric.Natural (Natural)
 import Prelude
 
+import qualified Data.Char as Unicode
+
 main :: IO ()
 main = hspec $ do
 
@@ -116,3 +125,31 @@
                 let f x = CaseRefinement.validateString x :: Maybe (ASCII'upper Text)
                 f "HELLO" `shouldBe` Just (asciiCaseUnsafe "HELLO")
                 f "Hello" `shouldBe` Nothing
+
+    describe "case conversion" $ do
+
+        describe "toCaseChar" $ do
+            let check :: forall a. Eq a => Superset.CharSuperset a => Expectation
+                check =
+                    ([UpperCase, LowerCase] & Foldable.all (\c ->
+                        ASCII.allCharacters & Foldable.all (\x ->
+                            Superset.toCaseChar c (Superset.fromChar @a x)
+                                == Superset.fromChar @a (Case.toCase c x)
+                    ))) `shouldBe` True
+            it "ASCII.Char" $ check @ASCII.Char
+            it "Unicode.Char" $ check @Unicode.Char
+            it "Natural" $ check @Natural
+            it "Int" $ check @Int
+            it "Word8" $ check @Word8
+
+        describe "toCaseString" $ do
+            it "Text" $ do
+                let x = "012 abc DEF ﬓ" :: Text
+                Superset.toCaseString UpperCase x `shouldBe` "012 ABC DEF ﬓ"
+                Superset.toCaseString LowerCase x `shouldBe` "012 abc def ﬓ"
+
+        describe "refineStringToCase" $ do
+            it "Text" $ do
+                let x = asciiUnsafe "Hi!" :: ASCII Text
+                CaseRefinement.refineStringToCase x `shouldBe` (asciiCaseUnsafe "HI!" :: ASCII'upper Text)
+                CaseRefinement.refineStringToCase x `shouldBe` (asciiCaseUnsafe "hi!" :: ASCII'lower Text)
