Skip to content

Commit 341446c

Browse files
authored
Merge pull request #12 from well-typed/edsko/fix-show
Fix show and prepare for release
2 parents 279ca0c + 360fea8 commit 341446c

File tree

3 files changed

+64
-29
lines changed

3 files changed

+64
-29
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Revision history for basic-sop
2+
3+
## 0.3.0 -- 2023-11-08
4+
5+
* Started CHANGELOG.md
6+
* Compatibility with ghc up to 9.8 (#9, tomjaguarpaw)
7+
* Correct parenthesis, avoid spurious I (#10, tomjaguarpaw)
8+
* Dropped support for ghc prior to 8.10.7
9+
10+

basic-sop.cabal

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: basic-sop
2-
version: 0.2.0.3
2+
version: 0.3.0
33
synopsis: Basic examples and functions for generics-sop
44
description:
55
This library contains various small examples of generic functions
@@ -15,8 +15,9 @@ author: Edsko de Vries <[email protected]>, Andres Löh <andres@
1515
maintainer: [email protected]
1616
category: Generics
1717
build-type: Simple
18-
cabal-version: >=1.10
19-
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
18+
cabal-version: 1.24
19+
extra-doc-files: CHANGELOG.md
20+
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
2021

2122
source-repository head
2223
type: git

src/Generics/SOP/Show.hs

Lines changed: 50 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
-- This module contains a generic show function defined using
44
-- @generics-sop@.
55
--
6-
module Generics.SOP.Show (gshow) where
6+
module Generics.SOP.Show (gshowsPrec, gshow) where
77

8-
import Data.List (intercalate)
8+
import Data.List (intersperse)
99

1010
import Generics.SOP
1111

@@ -16,44 +16,68 @@ import Generics.SOP
1616
-- 'deriving Show'.
1717
--
1818
-- It serves as an example of an SOP-style generic function that makes
19-
-- use of metadata. However, it does currently not handle parentheses
20-
-- correctly, and is therefore not really usable as a replacement.
19+
-- use of metadata.
2120
--
22-
-- If you want to use it anyway on a datatype @T@ for which you have
23-
-- a 'Generics.SOP.Generic' instance, you can use 'gshow' as follows:
21+
-- If you want to use it on a datatype @T@ for which you have a
22+
-- 'Generics.SOP.Generic' instance, you can use 'gshowsPrec' as
23+
-- follows:
2424
--
2525
-- > instance Show T where
26-
-- > show = gshow
26+
-- > showsPrec = gshowsPrec
2727
--
28-
gshow :: forall a. (Generic a, HasDatatypeInfo a, All2 Show (Code a))
29-
=> a -> String
30-
gshow a =
31-
gshow' (constructorInfo (datatypeInfo (Proxy :: Proxy a))) (from a)
28+
gshowsPrec :: forall a. (Generic a, HasDatatypeInfo a, All2 Show (Code a))
29+
=> Int -> a -> ShowS
30+
gshowsPrec prec a =
31+
gshowsPrec' prec (constructorInfo (datatypeInfo (Proxy :: Proxy a))) (from a)
3232

33-
gshow' :: (All2 Show xss, SListI xss) => NP ConstructorInfo xss -> SOP I xss -> String
34-
gshow' cs (SOP sop) = hcollapse $ hcliftA2 allp goConstructor cs sop
33+
gshow :: (Generic a, HasDatatypeInfo a, All2 Show (Code a)) => a -> String
34+
gshow a = gshowsPrec 0 a ""
3535

36-
goConstructor :: All Show xs => ConstructorInfo xs -> NP I xs -> K String xs
37-
goConstructor (Constructor n) args =
38-
K $ intercalate " " (n : args')
36+
gshowsPrec' :: (All2 Show xss, SListI xss) => Int -> NP ConstructorInfo xss -> SOP I xss -> ShowS
37+
gshowsPrec' prec cs (SOP sop) =
38+
hcollapse $ hcliftA2 allp (goConstructor prec) cs sop
39+
40+
goConstructor :: All Show xs => Int -> ConstructorInfo xs -> NP I xs -> K ShowS xs
41+
goConstructor prec (Constructor n) args =
42+
K $
43+
showParen
44+
(fixity <= prec)
45+
(foldr (.) id $ intersperse (showString " ") (showString n : args'))
3946
where
40-
args' :: [String]
41-
args' = hcollapse $ hcliftA p (K . show . unI) args
47+
args' :: [ShowS]
48+
args' = hcollapse $ hcliftA p (K . showsPrec 11 . unI) args
49+
50+
-- With fixity = 11 the parens will be shown only if the enclosing
51+
-- context is a function application. This is correct because
52+
-- function application is the only thing that binds tightly
53+
-- enough to force parens around this expression.
54+
fixity = 11
4255

43-
goConstructor (Record n ns) args =
44-
K $ n ++ " {" ++ intercalate ", " args' ++ "}"
56+
goConstructor prec (Record n ns) args =
57+
K $
58+
showParen
59+
(fixity <= prec)
60+
(showString n . showString " {" . foldr (.) id (intersperse (showString ", ") args') . showString "}")
4561
where
46-
args' :: [String]
62+
args' :: [ShowS]
4763
args' = hcollapse $ hcliftA2 p goField ns args
4864

49-
goConstructor (Infix n _ _) (arg1 :* arg2 :* Nil) =
50-
K $ show arg1 ++ " " ++ show n ++ " " ++ show arg2
65+
-- With fixity = 12 the parens will never be shown. This is
66+
-- correct because record construction binds tighter than even
67+
-- function application!
68+
fixity = 12
69+
70+
goConstructor prec (Infix n _ fixity) (I arg1 :* I arg2 :* Nil) =
71+
K $
72+
showParen
73+
(fixity <= prec)
74+
(showsPrec fixity arg1 . showString " " . showString n . showString " " . showsPrec fixity arg2)
5175
#if __GLASGOW_HASKELL__ < 800
52-
goConstructor (Infix _ _ _) _ = error "inaccessible"
76+
goConstructor _ (Infix _ _ _) _ = error "inaccessible"
5377
#endif
5478

55-
goField :: Show a => FieldInfo a -> I a -> K String a
56-
goField (FieldInfo field) (I a) = K $ field ++ " = " ++ show a
79+
goField :: Show a => FieldInfo a -> I a -> K ShowS a
80+
goField (FieldInfo field) (I a) = K $ showString field . showString " = " . showsPrec 0 a
5781

5882
p :: Proxy Show
5983
p = Proxy

0 commit comments

Comments
 (0)