diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,10 @@
+# Revision history for basic-sop
+
+## 0.3.0 -- 2023-11-08
+
+* Started CHANGELOG.md
+* Compatibility with ghc up to 9.8 (#9, tomjaguarpaw)
+* Correct parenthesis, avoid spurious I (#10, tomjaguarpaw)
+* Dropped support for ghc prior to 8.10.7
+
+
diff --git a/basic-sop.cabal b/basic-sop.cabal
--- a/basic-sop.cabal
+++ b/basic-sop.cabal
@@ -1,5 +1,5 @@
 name:                basic-sop
-version:             0.2.0.3
+version:             0.3.0
 synopsis:            Basic examples and functions for generics-sop
 description:
   This library contains various small examples of generic functions
@@ -15,8 +15,9 @@
 maintainer:          andres@well-typed.com
 category:            Generics
 build-type:          Simple
-cabal-version:       >=1.10
-tested-with:         GHC == 7.8.4, GHC == 7.10.3, GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.4, GHC == 8.6.5
+cabal-version:       1.24
+extra-doc-files:     CHANGELOG.md
+tested-with:         GHC==8.10.7, GHC==9.0.2, GHC==9.2.8, GHC==9.4.7, GHC==9.6.3, GHC==9.8.1
 
 source-repository head
   type:                git
@@ -30,9 +31,9 @@
                        Generics.SOP.NFData
   build-depends:       base                 >= 4.6    && < 5,
                        generics-sop         >= 0.2.3  && < 0.6,
-                       text                 >= 1.1    && < 1.3,
-                       QuickCheck           >= 2.7    && < 2.14,
-                       deepseq              >= 1.3    && < 1.5
+                       text                 >= 1.1    && < 2.2,
+                       QuickCheck           >= 2.7    && < 2.15,
+                       deepseq              >= 1.3    && < 1.6
   hs-source-dirs:      src
   default-language:    Haskell2010
   ghc-options:         -Wall
diff --git a/src/Generics/SOP/Show.hs b/src/Generics/SOP/Show.hs
--- a/src/Generics/SOP/Show.hs
+++ b/src/Generics/SOP/Show.hs
@@ -3,9 +3,9 @@
 -- This module contains a generic show function defined using
 -- @generics-sop@.
 --
-module Generics.SOP.Show (gshow) where
+module Generics.SOP.Show (gshowsPrec, gshow) where
 
-import Data.List (intercalate)
+import Data.List (intersperse)
 
 import Generics.SOP
 
@@ -16,44 +16,68 @@
 -- 'deriving Show'.
 --
 -- It serves as an example of an SOP-style generic function that makes
--- use of metadata. However, it does currently not handle parentheses
--- correctly, and is therefore not really usable as a replacement.
+-- use of metadata.
 --
--- If you want to use it anyway on a datatype @T@ for which you have
--- a 'Generics.SOP.Generic' instance, you can use 'gshow' as follows:
+-- If you want to use it on a datatype @T@ for which you have a
+-- 'Generics.SOP.Generic' instance, you can use 'gshowsPrec' as
+-- follows:
 --
 -- > instance Show T where
--- >   show = gshow
+-- >   showsPrec = gshowsPrec
 --
-gshow :: forall a. (Generic a, HasDatatypeInfo a, All2 Show (Code a))
-      => a -> String
-gshow a =
-  gshow' (constructorInfo (datatypeInfo (Proxy :: Proxy a))) (from a)
+gshowsPrec :: forall a. (Generic a, HasDatatypeInfo a, All2 Show (Code a))
+           => Int -> a -> ShowS
+gshowsPrec prec a =
+  gshowsPrec' prec (constructorInfo (datatypeInfo (Proxy :: Proxy a))) (from a)
 
-gshow' :: (All2 Show xss, SListI xss) => NP ConstructorInfo xss -> SOP I xss -> String
-gshow' cs (SOP sop) = hcollapse $ hcliftA2 allp goConstructor cs sop
+gshow :: (Generic a, HasDatatypeInfo a, All2 Show (Code a)) => a -> String
+gshow a = gshowsPrec 0 a ""
 
-goConstructor :: All Show xs => ConstructorInfo xs -> NP I xs -> K String xs
-goConstructor (Constructor n) args =
-    K $ intercalate " " (n : args')
+gshowsPrec' :: (All2 Show xss, SListI xss) => Int -> NP ConstructorInfo xss -> SOP I xss -> ShowS
+gshowsPrec' prec cs (SOP sop) =
+  hcollapse $ hcliftA2 allp (goConstructor prec) cs sop
+
+goConstructor :: All Show xs => Int -> ConstructorInfo xs -> NP I xs -> K ShowS xs
+goConstructor prec (Constructor n) args =
+    K $
+      showParen
+        (fixity <= prec)
+        (foldr (.) id $ intersperse (showString " ") (showString n : args'))
   where
-    args' :: [String]
-    args' = hcollapse $ hcliftA p (K . show . unI) args
+    args' :: [ShowS]
+    args' = hcollapse $ hcliftA p (K . showsPrec 11 . unI) args
 
-goConstructor (Record n ns) args =
-    K $ n ++ " {" ++ intercalate ", " args' ++ "}"
+    -- With fixity = 11 the parens will be shown only if the enclosing
+    -- context is a function application.  This is correct because
+    -- function application is the only thing that binds tightly
+    -- enough to force parens around this expression.
+    fixity = 11
+
+goConstructor prec (Record n ns) args =
+    K $
+      showParen
+        (fixity <= prec)
+        (showString n . showString " {" . foldr (.) id (intersperse (showString ", ") args') . showString "}")
   where
-    args' :: [String]
+    args' :: [ShowS]
     args' = hcollapse $ hcliftA2 p goField ns args
 
-goConstructor (Infix n _ _) (arg1 :* arg2 :* Nil) =
-    K $ show arg1 ++ " " ++ show n ++ " " ++ show arg2
+    -- With fixity = 12 the parens will never be shown.  This is
+    -- correct because record construction binds tighter than even
+    -- function application!
+    fixity = 12
+
+goConstructor prec (Infix n _ fixity) (I arg1 :* I arg2 :* Nil) =
+    K $
+      showParen
+        (fixity <= prec)
+        (showsPrec fixity arg1 . showString " " . showString n . showString " " . showsPrec fixity arg2)
 #if __GLASGOW_HASKELL__ < 800
-goConstructor (Infix _ _ _) _ = error "inaccessible"
+goConstructor _ (Infix _ _ _) _ = error "inaccessible"
 #endif
 
-goField :: Show a => FieldInfo a -> I a -> K String a
-goField (FieldInfo field) (I a) = K $ field ++ " = " ++ show a
+goField :: Show a => FieldInfo a -> I a -> K ShowS a
+goField (FieldInfo field) (I a) = K $ showString field . showString " = " . showsPrec 0 a
 
 p :: Proxy Show
 p = Proxy
