diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,21 @@
+## 0.4.0.0
+
+* Support GHCs 9.6 to 9.14.
+* Fix conflict with 'generic-lens' by using '{-# OVERLAPPING #-}'.
+
+## 0.3.0.2
+
+* Support GHCs 9.4 to 9.10, fix warnings.
+
+## 0.3.0.1
+
+* Bumped upper bounds for GHC 8.8.
+
+## 0.3.0.0
+
+* Added 'param', 'paramF'.
+* Export 'NamedF(Arg, ArgF)' as a bundle.
+
 ## 0.2.0.0
 
 * Removed 'Flag', 'named', 'Apply', 'apply'.
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,5 @@
 Copyright (c) 2018, Vladislav Zavialov
+              2018, Monadfix
 
 All rights reserved.
 
@@ -13,7 +14,7 @@
       disclaimer in the documentation and/or other materials provided
       with the distribution.
 
-    * Neither the name of Vladislav Zavialov nor the names of other
+    * Neither the name of Monadfix nor the names of other
       contributors may be used to endorse or promote products derived
       from this software without specific prior written permission.
 
diff --git a/named.cabal b/named.cabal
--- a/named.cabal
+++ b/named.cabal
@@ -1,5 +1,6 @@
+cabal-version:       2.4
 name:                named
-version:             0.2.0.0
+version:             0.4.0.0
 synopsis:            Named parameters (keyword arguments) for Haskell
 description:
     `named` is a lightweight library for named function parameters (keyword
@@ -28,34 +29,38 @@
     >                      ! #to "/target/path"
 
 
-license:             BSD3
+license:             BSD-3-Clause
 license-file:        LICENSE
 author:              Vladislav Zavialov
-maintainer:          Vladislav Zavialov <vlad.z.4096@gmail.com>
+maintainer:          Monadfix <hi@monadfix.com>
+homepage:            https://github.com/monadfix/named
+bug-reports:         https://github.com/monadfix/named/issues
 category:            Control
 build-type:          Simple
 extra-source-files:  ChangeLog.md
-tested-with:         GHC ==8.0.2, GHC ==8.2.2, GHC ==8.4.1
-cabal-version:       >=1.10
+tested-with:         GHC ==9.6.6, GHC ==9.10.3, GHC ==9.12.4, GHC ==9.14.1
 
 source-repository head
   type: git
-  location: git@github.com:int-index/named.git
+  location: git@github.com:monadfix/named.git
 
 library
   exposed-modules:     Named, Named.Internal
-  build-depends:       base >=4.9 && <4.12
+  build-depends:       base >=4.16 && <4.23
   hs-source-dirs:      src
-  default-language:    Haskell2010
+  default-language:    GHC2021
   ghc-options:         -Wall
                        -fno-warn-unticked-promoted-constructors
 
 test-suite regression
   type:                exitcode-stdio-1.0
   main-is:             Test.hs
-  build-depends:       base >=4.9 && <4.12,
-                       named
+  other-modules:       TestImport
+  build-depends:       base >=4.16 && <4.23,
+                       named,
+                       generic-lens,
+                       inspection-testing
   hs-source-dirs:      test
-  default-language:    Haskell2010
+  default-language:    GHC2021
   ghc-options:         -Wall
                        -fno-warn-missing-signatures
diff --git a/src/Named.hs b/src/Named.hs
--- a/src/Named.hs
+++ b/src/Named.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE PatternSynonyms, ExplicitNamespaces #-}
+{-# LANGUAGE ExplicitNamespaces #-}
 
 {- |
 
@@ -9,6 +9,8 @@
 * readability: their names serve as documentation at call site
 * safety: it is impossible to accidentally mix them up
 
+The required extensions are @OverloadedLabels@, @DataKinds@, and @TypeOperators@.
+
 Consider a function to replace a substring with another string:
 
 @
@@ -44,7 +46,7 @@
              '!' \#replacement "\/home\/username\/"
 @
 
-Functions can declare their parameter names in pattern bindings:
+Functions can declare their parameter names in pattern bindings (via the extension @ViewPatterns@):
 
 @
 replace ('arg' \#needle -> n) ('arg' \#replacement -> r) ('arg' \#haystack -> h) =
@@ -151,26 +153,53 @@
       '!' #handle logfile
 @
 
+= An issue with polymorphic return types
+
+A limitation of 'defaults' is that it is not possible to pass it to a function with a polymorphic return type. In particular: to mtl-style functions. The following code produces a compilation error:
+
+@
+foo :: "x" ':?' Int -> m Int
+
+bar :: m Int
+bar = foo '!' 'defaults'
+@
+
+A workaround is to return a newtype wrapper around @m@:
+
+@
+newtype M m a = M { runM :: m a }
+  deriving (Functor, Applicative, Monad)
+
+foo :: "x" ':?' Int -> M m Int
+
+bar :: M m Int
+bar = foo '!' 'defaults'
+
+bar' :: m Int
+bar' = runM (foo '!' 'defaults')
+@
+
+Note: the type signature of 'bar' is required.
+
+See [issue #15](https://github.com/monadfix/named/issues/15) "Problem with type inference caused by @! defaults@" for details.
 -}
 module Named
   (
-    -- * Calling functions
+    -- * Call site
     (!),
     WithParam(..),
+    param,
+    paramF,
     defaults,
 
-    -- * Types
+    -- * Definition site
     type (:!),
     type (:?),
-    NamedF,
-
-    -- * Patterns
+    NamedF(Arg, ArgF),
     Name(..),
     arg,
     argDef,
     argF,
-    pattern Arg,
-    pattern ArgF,
   ) where
 
 import Named.Internal
diff --git a/src/Named/Internal.hs b/src/Named/Internal.hs
--- a/src/Named/Internal.hs
+++ b/src/Named/Internal.hs
@@ -1,8 +1,6 @@
-{-# LANGUAGE KindSignatures, DataKinds, FlexibleInstances, FlexibleContexts,
-             FunctionalDependencies, TypeFamilies, TypeOperators,
-             PatternSynonyms, UndecidableInstances, ConstraintKinds,
-             TypeApplications, ScopedTypeVariables, CPP,
-             AllowAmbiguousTypes #-}
+{-# LANGUAGE AllowAmbiguousTypes, DataKinds, ExplicitNamespaces,
+             FunctionalDependencies, PatternSynonyms, TypeFamilies,
+             UndecidableInstances #-}
 
 module Named.Internal where
 
@@ -12,6 +10,7 @@
 import Data.Kind (Type)
 import GHC.TypeLits (Symbol, TypeError, ErrorMessage(..))
 import GHC.OverloadedLabels (IsLabel(..))
+import Data.Type.Equality (type (~))
 
 {- |
 
@@ -29,10 +28,7 @@
 -- | Match on an argument without specifying its name. See also: 'arg'.
 pattern Arg :: a -> name :! a
 pattern Arg a = ArgF (Identity a)
-
-#if MIN_VERSION_base(4,10,0)
 {-# COMPLETE Arg #-}
-#endif
 
 -- | Infix notation for the type of a named parameter.
 type name :! a = NamedF Identity a name
@@ -50,23 +46,47 @@
   injValue = Just
 
 instance (name ~ name', a ~ a', InjValue f) => IsLabel name (a -> NamedF f a' name') where
-#if MIN_VERSION_base(4,10,0)
   fromLabel a = ArgF (injValue a)
-#else
-  fromLabel _ a = ArgF (injValue a)
-#endif
   {-# INLINE fromLabel #-}
 
 newtype Param p = Param p
 
-instance (p ~ NamedF f a name, InjValue f) => IsLabel name (a -> Param p) where
-#if MIN_VERSION_base(4,10,0)
+-- It needs to be OVERLAPPING to avoid conflicts with 'generic-lens'.
+-- See the discussion for more context: https://github.com/monadfix/named/issues/8
+instance {-# OVERLAPPING #-} (p ~ NamedF f a name, InjValue f) => IsLabel name (a -> Param p) where
   fromLabel a = Param (fromLabel @name a)
-#else
-  fromLabel pName a = Param (fromLabel pName a)
-#endif
   {-# INLINE fromLabel #-}
 
+{- | Explicitly build a function parameter:
+
+@
+fn '!' 'param' \#param_name value
+@
+
+This is equivalent to the implicit notation:
+
+@
+fn '!' \#param_name value
+@
+
+-}
+param :: Name name -> a -> Param (name :! a)
+param _ a = Param (Arg a)
+
+{- | Explicitly build a function parameter inside an arity wrapper:
+
+@
+fn '!' 'paramF' \#param_name ('Identity' value)
+fn '!' 'paramF' \#param_name ('Just' value)
+fn '!' 'paramF' \#param_name 'Nothing'
+@
+
+This has no equivalent implicit notation.
+
+-}
+paramF :: Name name -> f a -> Param (NamedF f a name)
+paramF _ fa = Param (ArgF fa)
+
 {- | Supply a parameter to a function:
 
 @
@@ -151,11 +171,7 @@
 data Name (name :: Symbol) = Name
 
 instance name ~ name' => IsLabel name' (Name name) where
-#if MIN_VERSION_base(4,10,0)
   fromLabel = Name
-#else
-  fromLabel _ = Name
-#endif
   {-# INLINE fromLabel #-}
 
 {- |
diff --git a/test/Test.hs b/test/Test.hs
--- a/test/Test.hs
+++ b/test/Test.hs
@@ -1,22 +1,31 @@
 {-# LANGUAGE OverloadedLabels, DataKinds, TypeOperators, ViewPatterns,
-             PartialTypeSignatures #-}
+             PartialTypeSignatures, TemplateHaskell #-}
 
 {-# OPTIONS -fno-warn-partial-type-signatures #-}
 
 module Main where
 
 import Data.Maybe (fromMaybe)
+import Data.Functor (void)
 import Data.Function ((&))
+import Data.Generics.Labels () -- to ensure our instances won't conflict with IsLabel from generic-lens
 import Named
+import Test.Inspection
 
 test1 ::
   String ->
   "a" :! Bool ->
   "b" :! Bool ->
-  IO ()
-test1 "str" (arg #a -> True) (arg #b -> False) = return ()
-test1 _ _ _ = error "unexpected flags or str"
+  IO Bool
+test1 "str" (arg #a -> True) (arg #b -> False) = return True
+test1 _ _ _ = return False
 
+test1_raw :: String -> Bool -> Bool -> IO Bool
+test1_raw "str" True False = return True
+test1_raw _ _ _ = return False
+
+inspect $ 'test1 ==- 'test1_raw
+
 test1_1 =
   test1 "str"
     ! #a True
@@ -48,11 +57,20 @@
 test2 :: "x" :! Int -> Int
 test2 x = arg #x x * 2
 
+test2_raw :: Int -> Int
+test2_raw x = x * 2
+
+inspect $ 'test2 ==- 'test2_raw
+
 test2_1 :: Int
 test2_1 = test2 ! #x 5 + test2 ! #x 3
 
 test3 (arg #a -> a) (arg #b -> b) = a + b
 
+test3_raw a b = a + b
+
+inspect $ 'test3 ==- 'test3_raw
+
 -- must not typecheck:
 --     Couldn't match type ‘"a"’ with ‘"b"’
 --     arising from the overloaded label ‘#b’
@@ -60,35 +78,92 @@
 -- test3' :: _ => "a" :! _ -> _ :! "b" -> _
 -- test3' (arg #b -> a) (arg #a -> b) = a + b
 
--- test4 ::
---   "b" :! Bool ->
---   NamedF _ Char "x" ->
---   "y" :? Char ->
---   Char
+test4 ::
+  "b" :! Bool ->
+  NamedF _ Char "x" ->
+  "y" :? Char ->
+  Char
 test4
   (arg #b -> b)
   (argDef #x 'x' -> x)
   (ArgF y)
   = if b then x else (fromMaybe 'y' y)
 
+test4_raw :: Bool -> Maybe Char -> Maybe Char -> Char
+test4_raw b (fromMaybe 'x' -> x) y = if b then x else fromMaybe 'y' y
+
+inspect $ 'test4 ==- 'test4_raw
+
 test4_1 = test4 ! #b True ! defaults
 test4_2 = test4 ! #b False ! defaults
 test4_3 = test4 ! #x 'z' ! #b True ! defaults
 test4_4 = test4 ! defaults ! #b True
+test4_5 = test4 ! paramF #x (Just 'q') ! #b True ! defaults
+test4_6 = test4 ! paramF #x Nothing ! #b True ! #y '-'
 
+test5_1 :: ("bar" :! Int -> ()) -> ()
+test5_1 f = f ! #bar 3
+
+test5_1_raw :: (Int -> ()) -> ()
+test5_1_raw f = f 3
+
+inspect $ 'test5_1 ==- 'test5_1_raw
+
+test5_2 :: ("bar" :! Int -> ()) -> "bar" :! Int -> ()
+test5_2 f x = f x
+
+test5_2_raw :: (Int -> ()) -> Int -> ()
+test5_2_raw f x = f x
+
+inspect $ 'test5_2 ==- 'test5_2_raw
+
+test6 :: Maybe ("x" :! Int -> Int) -> Int
+test6 Nothing = 0
+test6 (Just f) = f ! #x 42
+
+test6_raw :: Maybe (Int -> Int) -> Int
+test6_raw Nothing = 0
+test6_raw (Just f) = f 42
+
+inspect $ 'test6 ==- 'test6_raw
+
+newtype M m a = M { runM :: m a }
+  deriving (Functor, Applicative, Monad)
+
+-- must typecheck:
+
+test7_1 :: "x" :? Int -> M m Int
+test7_1 = undefined
+
+test7_2 :: M m Int
+test7_2 = test7_1 ! defaults
+
+test7_3 :: m Int
+test7_3 = runM (test7_1 ! defaults)
+
+-- doesn't typecheck (yet):
+--
+-- test7_4 :: "x" :? Int -> m Int
+-- test7_4 = undefined
+
+-- test7_5 :: m Int
+-- test7_5 = test7_1 ! defaults
+
 main :: IO ()
 main = do
-  test1_1
-  test1_2
-  test1_3
-  test1_4
-  test1_5
-  test1_6
+  void test1_1
+  void test1_2
+  void test1_3
+  void test1_4
+  void test1_5
+  void test1_6
   test2_1 `mustBe` 16
   test4_1 `mustBe` 'x'
   test4_2 `mustBe` 'y'
   test4_3 `mustBe` 'z'
   test4_4 `mustBe` 'x'
+  test4_5 `mustBe` 'q'
+  test4_6 `mustBe` 'x'
 
 mustBe :: (Eq a, Show a) => a -> a -> IO ()
 mustBe a b
diff --git a/test/TestImport.hs b/test/TestImport.hs
new file mode 100644
--- /dev/null
+++ b/test/TestImport.hs
@@ -0,0 +1,3 @@
+module TestImport (module Named) where
+
+import Named (NamedF(Arg, ArgF))
