diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,23 @@
 # Revision history for aws-arn
 
+## 0.2.0.0 -- 2022-07-19
+
+* Rename `fromFoo`/`toFoo` to `renderFoo`/`parseFoo`:
+  - `Network.AWS.ARN.toARN` -> `Network.AWS.ARN.parseARN`
+  - `Network.AWS.ARN.fromARN` -> `Network.AWS.ARN.renderARN`
+  - `Network.AWS.ARN.Lambda.fromFunction` -> `Network.AWS.ARN.renderFunction`
+  - `Network.AWS.ARN.Lambda.toFunction` -> `Network.AWS.ARN.parseFunction`
+* Remove the leading underscore and prefix on record names. This makes
+  for a nicer interface when using the
+  [generic-lens](https://hackage.haskell.org/package/generic-lens) and
+  [generic-optics](https://hackage.haskell.org/package/generic-optics)
+  libraries, which are now the preferred way to lens into individual
+  fields.
+* Remove dependency on `lens`; depend instead on `profunctors` (to
+  provide `Prism'`s).
+* `Network.AWS.ARN.colons`: Provide a `Lens'` instead of an unlawful `Iso'`.
+* `Network.AWS.ARN.slashes`: Provide a `Lens'` instead of an unlawful `Iso'.`
+
 ## 0.1.0.1 -- 2021-12-16
 
 * Support GHC 9.0.1, GHC 9.2.1, and `hashable <1.5`.
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (C) 2020-2021 Bellroy Pty Ltd
+Copyright (C) 2020-2022 Bellroy Pty Ltd
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -4,8 +4,10 @@
 
 This library provides a type representing [Amazon Resource Names
 (ARNs)](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html),
-and parsing/unparsing functions for them. The provided optics make it
-very convenient to rewrite parts of ARNs.
+and parsing/unparsing functions for them. When combined with
+[`generic-lens`](https://hackage.haskell.org/package/generic-lens) or
+[`generic-optics`](https://hackage.haskell.org/package/generic-optics),
+the provided prisms make it very convenient to rewrite parts of ARNs.
 
 Start reading at the `Network.AWS.ARN` module, which defines the core
 data type and includes some examples.
@@ -30,56 +32,49 @@
 
 2. Define a record `Foo` to represent the parsed resource part of an
    ARN, and derive (at least) `Eq`, `Ord`, `Hashable`, `Show` and
-   `Generic`. Also generate lenses for its fields:
+   `Generic`:
 
    ```haskell
    data Function = Function
-   { _fName :: Text,
-     _fQualifier :: Maybe Text
+   { name :: Text,
+     qualifier :: Maybe Text
    }
    deriving (Eq, Ord, Hashable, Show, Generic)
-
-   $(makeLenses ''Function)
    ```
 
-3. Define `toFoo` and `fromFoo` functions that attempt to parse and
-   unparse the resource part of the ARN:
+3. Define `parseFoo` and `renderFoo` functions that attempt to parse
+   and unparse the resource part of the ARN:
 
    ```haskell
-   toFunction :: Text -> Maybe Function
-   fromFunction :: Function -> Text
+   parseFunction :: Text -> Maybe Function
+   renderFunction :: Function -> Text
    ```
 
-   **Remark:** While these names sound backwards compared to
-   `fromText` and `toText`, it means we can have multiple parsing
-   functions in a single service's module.
-
    **Remark:** If you need to write tests for these functions, the
    corresponding module should live at
    `test/Network/AWS/ARN/SomeAWSService/Test.hs`
 
 4. Define a `_Foo` `Prism'` that combines the parsing/unparsing
-   functions above:
+   functions above. Use the local definitions of prisms in
+   `Network.AWS.ARN.Internal.Lens`:
 
    ```haskell
    _Function :: Prism' Text Function
    _Function = prism' fromFunction toFunction
    ```
 
-5. Add the records, its fields, its parsing/unparsing functions, and
-   its optics to the service module's export list:
+5. Add the records, their fields, its parsing/unparsing functions, and
+   prisms to the service module's export list:
 
    ```haskell
    module Network.AWS.ARN.Lambda
      ( -- * Functions
        Function (..),
-       toFunction,
-       fromFunction,
+       parseFunction,
+       renderFunction,
 
-       -- ** Function Optics
+       -- ** Prisms
        _Function,
-       fName,
-       fQualifier,
      )
    ```
 
diff --git a/aws-arn.cabal b/aws-arn.cabal
--- a/aws-arn.cabal
+++ b/aws-arn.cabal
@@ -1,14 +1,17 @@
 cabal-version:      2.2
 name:               aws-arn
-version:            0.1.0.1
+version:            0.2.0.0
 synopsis:
   Types and optics for manipulating Amazon Resource Names (ARNs)
 
 description:
+
   This library provides a type representing [Amazon Resource Names
   (ARNs)](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html),
-  and parsing/unparsing functions for them. The provided optics make
-  it very convenient to rewrite parts of ARNs.
+  and parsing/unparsing functions for them. The provided prisms, when
+  combined with [generic-lens](https://hackage.haskell.org/package/generic-lens)
+  or [generic-optics](https://hackage.haskell.org/package/generic-optics),
+  make it very convenient to rewrite parts of ARNs.
   .
   Start reading at the "Network.AWS.ARN" module, which defines the
   core data type and includes some examples.
@@ -28,14 +31,16 @@
 license-file:       LICENSE
 author:             Bellroy Tech Team <haskell@bellroy.com>
 maintainer:         Bellroy Tech Team <haskell@bellroy.com>
-copyright:          Copyright (C) 2020-2021 Bellroy Pty Ltd
+copyright:          Copyright (C) 2020-2022 Bellroy Pty Ltd
 category:           AWS, Cloud
 build-type:         Simple
 extra-source-files:
   CHANGELOG.md
   README.md
 
-tested-with:        GHC ==8.6.5 || ==8.8.4 || ==8.10.7 || ==9.0.1
+-- Once hlint supports GHC 9.2.2, we can add it to tested-with;
+-- Otherwise a hlint build failure breaks CI.
+tested-with:        GHC ==8.6.5 || ==8.8.4 || ==8.10.7 || ==9.0.2
 
 common opts
   default-language: Haskell2010
@@ -50,13 +55,15 @@
   build-depends:
     , base             >=4.12   && <4.17
     , deriving-compat  >=0.5.10 && <0.7
-    , lens             >=4.18.1 && <5.2
-    , text             ^>=1.2.3
+    , profunctors      >=5.0    && <5.7
+    , tagged           ^>=0.8
+    , text             ^>=1.2.3 || ^>=2.0
 
 library
   import:          opts, deps
   exposed-modules:
     Network.AWS.ARN
+    Network.AWS.ARN.Internal.Lens
     Network.AWS.ARN.Lambda
 
   build-depends:   hashable >=1.3.0.0 && <1.5
@@ -74,11 +81,10 @@
   ghc-options:        -threaded
   build-depends:
     , aws-arn
-    , tasty           ^>=1.4.0.2
-    , tasty-discover  ^>=4.2.2
-    , tasty-hunit     ^>=0.10.0.3
+    , tasty        ^>=1.4.0.2
+    , tasty-hunit  ^>=0.10.0.3
 
-  build-tool-depends: tasty-discover:tasty-discover -any
+  build-tool-depends: tasty-discover:tasty-discover >=4.2.2 && <5.1
 
 source-repository head
   type:     git
diff --git a/src/Network/AWS/ARN.hs b/src/Network/AWS/ARN.hs
--- a/src/Network/AWS/ARN.hs
+++ b/src/Network/AWS/ARN.hs
@@ -10,7 +10,7 @@
 -- |
 --
 -- Module      : Network.AWS.ARN
--- Copyright   : (C) 2020-2021 Bellroy Pty Ltd
+-- Copyright   : (C) 2020-2022 Bellroy Pty Ltd
 -- License     : BSD-3-Clause
 -- Maintainer  : Bellroy Tech Team <haskell@bellroy.com>
 -- Stability   : experimental
@@ -33,24 +33,23 @@
 -- every endpoint in the stage:
 --
 -- @
+-- {-# LANGUAGE OverloadedLabels #-}
+-- -- This provides the necessary instances from generic-lens
+-- import Data.Generics.Labels ()
+--
 -- -- Returns "arn:aws:execute-api:us-east-1:123456789012:my-spiffy-api\/stage\/*"
 -- let
 --   authorizerSampleARN = "arn:aws:execute-api:us-east-1:123456789012:my-spiffy-api\/stage\/GET\/some\/deep\/path"
 -- in
---   over ('_ARN' . 'arnResource' . 'slashes') (\\parts -> take 2 parts ++ ["*"]) authorizerSampleARN
+--   over ('_ARN' . #resource . 'slashes') (\\parts -> take 2 parts ++ ["*"]) authorizerSampleARN
 -- @
 module Network.AWS.ARN
   ( ARN (..),
-    toARN,
-    fromARN,
+    parseARN,
+    renderARN,
 
-    -- * ARN Optics
+    -- * ARN Prism
     _ARN,
-    arnPartition,
-    arnService,
-    arnRegion,
-    arnAccount,
-    arnResource,
 
     -- * Utility Optics
     colons,
@@ -58,40 +57,44 @@
   )
 where
 
-import Control.Lens (Iso', Prism', iso, makeLenses, prism')
 import Data.Eq.Deriving (deriveEq1)
 import Data.Hashable (Hashable)
 import Data.Hashable.Lifted (Hashable1)
+import Data.List.NonEmpty (NonEmpty)
+import qualified Data.List.NonEmpty as NonEmpty
 import Data.Ord.Deriving (deriveOrd1)
 import Data.Text (Text)
 import qualified Data.Text as T
 import GHC.Generics (Generic, Generic1)
+import Network.AWS.ARN.Internal.Lens (Lens', Prism', prism')
 import Text.Show.Deriving (deriveShow1)
 
--- $setup
--- >>> :set -XOverloadedStrings
--- >>> import Control.Lens
-
--- | A parsed ARN. Either use the '_ARN' 'Prism'', or the 'toARN' and
--- 'fromARN' functions to convert @'Text' \<-\> 'ARN'@.  The
--- '_arnResource' part of an ARN will often contain colon- or
+-- | A parsed ARN. Either use the '_ARN' 'Prism'', or the 'parseARN' and
+-- 'renderARN' functions to convert @'Text' \<-\> 'ARN'@.  The
+-- 'resource' part of an ARN will often contain colon- or
 -- slash-separated parts which precisely identify some resource. If
 -- there is no service-specific module (see below), the 'colons' and
--- 'slashes' @'Control.Lens.Iso''@s in this module can pick apart the
--- `_arnResource` field.
+-- 'slashes' lenses in this module can pick apart the `resource`
+-- field.
 --
+-- If you want lenses into individual fields, use the
+-- [@generic-lens@](https://hackage.haskell.org/package/generic-lens)
+-- or
+-- [@generic-optics@](https://hackage.haskell.org/package/generic-optics)
+-- libraries.
+--
 -- == Service-Specific Modules
 --
 -- Modules like "Network.AWS.ARN.Lambda" provide types to parse the
 -- resource part of an ARN into something more specific:
 --
 -- @
--- -- Remark: Lambda._Function :: 'Prism'' 'Text' Lambda.Function
+-- -- Remark: Lambda._Function :: Prism' Text Lambda.Function
 -- -- Returns: Just "the-coolest-function-ever"
 -- let
 --   functionARN = "arn:aws:lambda:us-east-1:123456789012:function:the-coolest-function-ever:Alias"
 -- in
---   functionARN ^? _ARN . arnResource . Lambda._Function . Lambda.fName
+--   functionARN ^? _ARN . #resource . Lambda._Function . #name
 -- @
 --
 -- You can also use 'ARN'\'s 'Traversable' instance and
@@ -99,14 +102,16 @@
 -- resource type in 'ARN'\'s type variable:
 --
 -- @
--- '_ARN' . 'Control.Lens.Prism.below' Lambda._Function :: 'Prism'' 'Text' ('ARN' Lambda.Function)
+-- '_ARN' . 'Control.Lens.Prism.below' Lambda._Function :: Prism' Text ('ARN' Lambda.Function)
 -- @
+--
+-- @since 0.1.0.0
 data ARN r = ARN
-  { _arnPartition :: Text,
-    _arnService :: Text,
-    _arnRegion :: Text,
-    _arnAccount :: Text,
-    _arnResource :: r
+  { partition :: Text,
+    service :: Text,
+    region :: Text,
+    account :: Text,
+    resource :: r
   }
   deriving
     ( Eq,
@@ -120,71 +125,75 @@
       Traversable
     )
 
-$(makeLenses ''ARN)
 $(deriveEq1 ''ARN)
 $(deriveOrd1 ''ARN)
 $(deriveShow1 ''ARN)
 
 deriving instance Hashable1 ARN
 
-toARN :: Text -> Maybe (ARN Text)
-toARN t = case T.splitOn ":" t of
+-- | @since 0.2.0.0
+parseARN :: Text -> Maybe (ARN Text)
+parseARN t = case T.splitOn ":" t of
   ("arn" : part : srv : reg : acc : res) ->
     Just $
       ARN
-        { _arnPartition = part,
-          _arnService = srv,
-          _arnRegion = reg,
-          _arnAccount = acc,
-          _arnResource = T.intercalate ":" res
+        { partition = part,
+          service = srv,
+          region = reg,
+          account = acc,
+          resource = T.intercalate ":" res
         }
   _ -> Nothing
 
-fromARN :: ARN Text -> Text
-fromARN arn =
+-- | @since 0.2.0.0
+renderARN :: ARN Text -> Text
+renderARN arn =
   T.intercalate
     ":"
     [ "arn",
-      _arnPartition arn,
-      _arnService arn,
-      _arnRegion arn,
-      _arnAccount arn,
-      _arnResource arn
+      partition arn,
+      service arn,
+      region arn,
+      account arn,
+      resource arn
     ]
 
+-- | @since 0.1.0.0
 _ARN :: Prism' Text (ARN Text)
-_ARN = prism' fromARN toARN
+_ARN = prism' renderARN parseARN
 {-# INLINE _ARN #-}
 
 -- | Split a 'Text' into colon-separated parts.
 --
--- This is not truly a lawful 'Iso'', but it is useful. The 'Iso''
--- laws are violated for lists whose members contain @':'@:
---
--- >>> [":"] ^. from colons . colons
--- ["",""]
+-- This is useful for editing the resource part of an ARN:
 --
--- The laws are also violated on empty lists:
+-- >>> "foo:bar:baz" & colons . ix 1 .~ "quux"
+-- "foo:quux:baz"
 --
--- >>> [] ^. from colons . colons
--- [""]
+-- Writing back through the lens ignores the string it is applied to:
 --
--- However, it is still a useful tool:
+-- >>> "Hello, world!" & colons .~ "dude" :| ["sweet"]
+-- "dude:sweet"
 --
--- >>> "foo:bar:baz" & colons . ix 1 .~ "quux"
--- "foo:quux:baz"
-colons :: Iso' Text [Text]
-colons = iso (T.splitOn ":") (T.intercalate ":")
+-- @since 0.2.0.0
+colons :: Lens' Text (NonEmpty Text)
+colons = splitOn ":"
 {-# INLINE colons #-}
 
 -- | Split a 'Text' into slash-separated parts.
 --
--- This is not truly a lawful 'Iso'', but it is useful:
---
 -- >>> "foo/bar/baz" ^. slashes
--- ["foo","bar","baz"]
+-- "foo" :| ["bar","baz"]
 --
--- Similar caveats to 'colons' apply here.
-slashes :: Iso' Text [Text]
-slashes = iso (T.splitOn "/") (T.intercalate "/")
+-- Similar caveats to 'colons' apply.
+--
+-- @since 0.2.0.0
+slashes :: Lens' Text (NonEmpty Text)
+slashes = splitOn "/"
 {-# INLINE slashes #-}
+
+splitOn :: Text -> Lens' Text (NonEmpty Text)
+splitOn delim f t =
+  T.intercalate delim . NonEmpty.toList
+    <$> f (NonEmpty.fromList (T.splitOn delim t))
+{-# INLINE splitOn #-}
diff --git a/src/Network/AWS/ARN/Internal/Lens.hs b/src/Network/AWS/ARN/Internal/Lens.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/AWS/ARN/Internal/Lens.hs
@@ -0,0 +1,60 @@
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+-- |
+--
+-- Module      : Network.AWS.ARN.Internal.Lens
+-- Copyright   : (C) 2020-2022 Bellroy Pty Ltd
+-- License     : BSD-3-Clause
+-- Maintainer  : Bellroy Tech Team <haskell@bellroy.com>
+-- Stability   : experimental
+--
+-- Reimplement a few lens types and combinators to keep the dependency
+-- footprint down.
+module Network.AWS.ARN.Internal.Lens where
+
+import Data.Functor.Const (Const (..))
+import Data.Functor.Identity (Identity (..))
+import Data.Monoid (First (..))
+import Data.Profunctor (dimap)
+import Data.Profunctor.Choice (Choice (..))
+import Data.Tagged (Tagged (..))
+
+type Lens' s a = forall f. Functor f => (a -> f a) -> s -> f s
+
+type Setter s a = (a -> Identity a) -> s -> Identity s
+
+set :: Setter s a -> a -> s -> s
+set l = over l . const
+{-# INLINE set #-}
+
+over :: Setter s a -> (a -> a) -> s -> s
+over l f = runIdentity . l (Identity . f)
+{-# INLINE over #-}
+
+type Prism' s a =
+  forall p f. (Choice p, Applicative f) => p a (f a) -> p s (f s)
+
+prism' :: forall s a. (a -> s) -> (s -> Maybe a) -> Prism' s a
+prism' to from p = dimap from' to' $ right' p
+  where
+    to' :: Applicative f => Either s (f a) -> f s
+    to' = either pure (fmap to)
+
+    from' :: s -> Either s a
+    from' s = maybe (Left s) Right $ from s
+{-# INLINE prism' #-}
+
+preview :: Prism' s a -> s -> Maybe a
+preview p s = (getFirst . getConst . ($ s)) $ p (Const . First . Just)
+{-# INLINE preview #-}
+
+review :: Prism' s a -> a -> s
+review p = runIdentity . unTagged . p . Tagged . Identity
+{-# INLINE review #-}
+
+(^?) :: s -> Prism' s a -> Maybe a
+s ^? p = preview p s
+{-# INLINE (^?) #-}
+
+infixl 8 ^?
diff --git a/src/Network/AWS/ARN/Lambda.hs b/src/Network/AWS/ARN/Lambda.hs
--- a/src/Network/AWS/ARN/Lambda.hs
+++ b/src/Network/AWS/ARN/Lambda.hs
@@ -1,71 +1,67 @@
 {-# LANGUAGE DeriveAnyClass #-}
 {-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell #-}
 {-# OPTIONS_HADDOCK show-extensions #-}
 
 -- |
 --
 -- Module      : Network.AWS.ARN.Lambda
--- Copyright   : (C) 2020-2021 Bellroy Pty Ltd
+-- Copyright   : (C) 2020-2022 Bellroy Pty Ltd
 -- License     : BSD-3-Clause
 -- Maintainer  : Bellroy Tech Team <haskell@bellroy.com>
 -- Stability   : experimental
 module Network.AWS.ARN.Lambda
   ( -- * Functions
     Function (..),
-    toFunction,
-    fromFunction,
+    parseFunction,
+    renderFunction,
 
-    -- ** Function Optics
+    -- ** Prisms
     _Function,
-    fName,
-    fQualifier,
   )
 where
 
-import Control.Lens
 import Data.Hashable (Hashable)
 import Data.Maybe (maybeToList)
 import Data.Text (Text)
 import qualified Data.Text as T
 import GHC.Generics (Generic)
-
--- $setup
--- >>> :set -XOverloadedStrings
--- >>> import Control.Lens
+import Network.AWS.ARN.Internal.Lens (Prism', prism')
 
 -- | An AWS Lambda function name, and optional alias/version qualifier.
 --
 -- >>> "function:helloworld" ^? _Function
--- Just (Function {_fName = "helloworld", _fQualifier = Nothing})
+-- Just (Function {name = "helloworld", qualifier = Nothing})
 --
 -- >>> "function:helloworld:$LATEST" ^? _Function
--- Just (Function {_fName = "helloworld", _fQualifier = Just "$LATEST"})
+-- Just (Function {name = "helloworld", qualifier = Just "$LATEST"})
 --
 -- >>> "function:helloworld:42" ^? _Function
--- Just (Function {_fName = "helloworld", _fQualifier = Just "42"})
+-- Just (Function {name = "helloworld", qualifier = Just "42"})
+--
+-- @since 0.2.0.0
 data Function = Function
-  { _fName :: Text,
-    _fQualifier :: Maybe Text
+  { name :: Text,
+    qualifier :: Maybe Text
   }
   deriving (Eq, Ord, Hashable, Show, Generic)
 
-$(makeLenses ''Function)
-
-toFunction :: Text -> Maybe Function
-toFunction t = case T.splitOn ":" t of
-  ("function" : name : qual) ->
-    Just (Function name) <*> case qual of
+-- | @since 0.2.0.0
+parseFunction :: Text -> Maybe Function
+parseFunction t = case T.splitOn ":" t of
+  ("function" : nam : qual) ->
+    Just (Function nam) <*> case qual of
       [q] -> Just $ Just q
       [] -> Just Nothing
       _ -> Nothing
   _ -> Nothing
 
-fromFunction :: Function -> Text
-fromFunction f =
+-- | @since 0.2.0.0
+renderFunction :: Function -> Text
+renderFunction f =
   T.intercalate ":" $
-    ["function", _fName f] ++ maybeToList (_fQualifier f)
+    ["function", name f] ++ maybeToList (qualifier f)
 
+-- | @since 0.1.0.0
 _Function :: Prism' Text Function
-_Function = prism' fromFunction toFunction
+_Function = prism' renderFunction parseFunction
diff --git a/test/Network/AWS/ARN/Lambda/Test.hs b/test/Network/AWS/ARN/Lambda/Test.hs
--- a/test/Network/AWS/ARN/Lambda/Test.hs
+++ b/test/Network/AWS/ARN/Lambda/Test.hs
@@ -1,8 +1,10 @@
+{-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
 
 module Network.AWS.ARN.Lambda.Test where
 
-import Control.Lens (set, (^?))
+import Data.Text (Text)
+import Network.AWS.ARN.Internal.Lens (Lens', set, (^?))
 import Network.AWS.ARN.Lambda
 import Test.Tasty
 import Test.Tasty.HUnit
@@ -31,3 +33,6 @@
             ]
         ]
     ]
+
+fQualifier :: Lens' Function (Maybe Text)
+fQualifier l f@Function {qualifier} = (\q -> f {qualifier = q}) <$> l qualifier
diff --git a/test/Network/AWS/ARN/Test.hs b/test/Network/AWS/ARN/Test.hs
--- a/test/Network/AWS/ARN/Test.hs
+++ b/test/Network/AWS/ARN/Test.hs
@@ -1,10 +1,13 @@
+{-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
 
 module Network.AWS.ARN.Test where
 
-import Control.Lens (over, preview, review)
+import Data.List.NonEmpty (NonEmpty (..))
+import qualified Data.List.NonEmpty as NonEmpty
 import Data.Text (Text)
 import Network.AWS.ARN
+import Network.AWS.ARN.Internal.Lens (Lens', over, preview, review)
 import Test.Tasty
 import Test.Tasty.HUnit
 
@@ -15,14 +18,14 @@
     [ testGroup
         "basic tests"
         [ testCase "inspect function name and alias of Lambda ARN" $
-            (_arnResource <$> toARN aliasedLambdaSampleARN)
+            (resource <$> parseARN aliasedLambdaSampleARN)
               @?= Just "function:the-coolest-function-ever:Alias",
           testCase "parses empty region OK" $
-            (_arnRegion <$> toARN s3FileSampleARN) @?= Just "",
+            (region <$> parseARN s3FileSampleARN) @?= Just "",
           testCase "parses empty account OK" $
-            (_arnAccount <$> toARN s3FileSampleARN) @?= Just "",
+            (account <$> parseARN s3FileSampleARN) @?= Just "",
           testCase "rejects non-ARNs" $
-            toARN sampleNotAnARN @?= Nothing
+            parseARN sampleNotAnARN @?= Nothing
         ],
       testGroup
         "optic tests"
@@ -30,7 +33,10 @@
             (review _ARN <$> preview _ARN authorizerSampleARN)
               @?= Just authorizerSampleARN,
           testCase "edit path of Lambda Authorizer ARN" $
-            over (_ARN . arnResource . slashes) (\parts -> take 2 parts ++ ["*"]) authorizerSampleARN
+            over
+              (_ARN . arnResource . slashes)
+              (\parts -> prependList (NonEmpty.take 2 parts) ("*" :| []))
+              authorizerSampleARN
               @?= "arn:aws:execute-api:us-east-1:123456789012:my-spiffy-api/stage/*"
         ]
     ]
@@ -46,3 +52,13 @@
 
 sampleNotAnARN :: Text
 sampleNotAnARN = "//library.googleapis.com/shelves/shelf1/books/book2"
+
+arnResource :: Lens' (ARN a) a
+arnResource l a@(ARN {resource}) = (\r -> a {resource = r}) <$> l resource
+
+-- In Data.List.NonEmpty as of base >=4.16, but not worth breaking
+-- compatibility just for this. Remove once the three latest GHC major
+-- releases are all base >=4.16.
+prependList :: [a] -> NonEmpty a -> NonEmpty a
+prependList [] ys = ys
+prependList (x : xs) (y :| ys) = x :| xs ++ y : ys
