Switch from manual implementations to automatically derived implementations of Foldable/Traversable, and add Data and Typeable instances
Getty Ritter
9 years ago
1 | {-# LANGUAGE DeriveDataTypeable #-} | |
2 | {-# LANGUAGE DeriveFoldable #-} | |
1 | 3 | {-# LANGUAGE DeriveFunctor #-} |
4 | {-# LANGUAGE DeriveTraversable #-} | |
2 | 5 | {-# LANGUAGE TypeFamilies #-} |
3 | 6 | |
4 | 7 | module Data.SCargot.Repr |
14 | 17 | , fromWellFormed |
15 | 18 | ) where |
16 | 19 | |
20 | import Data.Data (Data) | |
17 | 21 | import Data.Foldable (Foldable(..)) |
18 | 22 | import Data.Monoid (Monoid(..), (<>)) |
19 | 23 | import Data.Traversable (Traversable(..)) |
24 | import Data.Typeable (Typeable) | |
20 | 25 | import GHC.Exts (IsList(..), IsString(..)) |
21 | 26 | |
22 | 27 | -- | All S-Expressions can be understood as a sequence |
27 | 32 | = SCons (SExpr atom) (SExpr atom) |
28 | 33 | | SAtom atom |
29 | 34 | | SNil |
30 |
deriving (Eq, Show, Read, Functor, Data |
|
35 | deriving (Eq, Show, Read, Functor, Data, Typeable, Foldable, Traversable) | |
31 | 36 | |
32 | 37 | instance IsString atom => IsString (SExpr atom) where |
33 | 38 | fromString = SAtom . fromString |
39 | 44 | where go (SCons x xs) = x : go xs |
40 | 45 | go SNil = [] |
41 | 46 | go (SAtom {}) = error "Unable to turn atom into list" |
42 | ||
43 | instance Foldable SExpr where | |
44 | foldMap _ SNil = mempty | |
45 | foldMap f (SAtom a) = f a | |
46 | foldMap f (SCons x y) = foldMap f x <> foldMap f y | |
47 | ||
48 | instance Traversable SExpr where | |
49 | traverse f SNil = pure SNil | |
50 | traverse f (SAtom a) = SAtom <$> f a | |
51 | traverse f (SCons x y) = SCons <$> traverse f x <*> traverse f y | |
52 | 47 | |
53 | 48 | -- | Sometimes the cons-based interface is too low |
54 | 49 | -- level, and we'd rather have the lists themselves |
65 | 60 | = RSList [RichSExpr atom] |
66 | 61 | | RSDotted [RichSExpr atom] atom |
67 | 62 | | RSAtom atom |
68 |
deriving (Eq, Show, Read, Functor |
|
63 | deriving (Eq, Show, Read, Functor, Data, Typeable, Foldable, Traversable) | |
69 | 64 | |
70 | 65 | instance IsString atom => IsString (RichSExpr atom) where |
71 | 66 | fromString = RSAtom . fromString |
97 | 92 | fromRich (RSList xs) = foldr SCons SNil (map fromRich xs) |
98 | 93 | fromRich (RSDotted xs x) = foldr SCons (SAtom x) (map fromRich xs) |
99 | 94 | |
100 | instance Foldable RichSExpr where | |
101 | foldMap f (RSAtom a) = f a | |
102 | foldMap f (RSList xs) = mconcat $ map (foldMap f) xs | |
103 | foldMap f (RSDotted xs y) = mconcat (map (foldMap f) xs) <> f y | |
104 | ||
105 | instance Traversable RichSExpr where | |
106 | traverse f (RSAtom a) = RSAtom <$> f a | |
107 | traverse f (RSList xs) = RSList <$> sequenceA (map (traverse f) xs) | |
108 | traverse f (RSDotted xs y) = RSDotted <$> sequenceA (map (traverse f) xs) | |
109 | <*> f y | |
110 | ||
111 | 95 | -- | A well-formed s-expression is one which does not |
112 | 96 | -- contain any dotted lists. This means that not |
113 | 97 | -- every value of @SExpr a@ can be converted to a |
116 | 100 | data WellFormedSExpr atom |
117 | 101 | = WFSList [WellFormedSExpr atom] |
118 | 102 | | WFSAtom atom |
119 |
deriving (Eq, Show, Read, Functor |
|
103 | deriving (Eq, Show, Read, Functor, Data, Typeable, Foldable, Traversable) | |
120 | 104 | |
121 | 105 | instance IsList (WellFormedSExpr atom) where |
122 | 106 | type Item (WellFormedSExpr atom) = WellFormedSExpr atom |
126 | 110 | |
127 | 111 | instance IsString atom => IsString (WellFormedSExpr atom) where |
128 | 112 | fromString = WFSAtom . fromString |
129 | ||
130 | instance Foldable WellFormedSExpr where | |
131 | foldMap f (WFSAtom a) = f a | |
132 | foldMap f (WFSList xs) = mconcat $ map (foldMap f) xs | |
133 | ||
134 | instance Traversable WellFormedSExpr where | |
135 | traverse f (WFSAtom a) = WFSAtom <$> f a | |
136 | traverse f (WFSList xs) = WFSList <$> sequenceA (map (traverse f) xs) | |
137 | 113 | |
138 | 114 | -- | This will be @Nothing@ if the argument contains an |
139 | 115 | -- improper list. It should hold that |