Repr.hs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. {-# LANGUAGE DeriveFunctor #-}
  2. {-# LANGUAGE TypeFamilies #-}
  3. module Data.SCargot.Repr
  4. ( -- * Elementary SExpr representation
  5. SExpr(..)
  6. -- * Rich SExpr representation
  7. , RichSExpr(..)
  8. , toRich
  9. , fromRich
  10. -- * Well-Formed SExpr representation
  11. , WellFormedSExpr(..)
  12. , toWellFormed
  13. , fromWellFormed
  14. ) where
  15. import Data.Foldable (Foldable(..))
  16. import Data.Monoid (Monoid(..), (<>))
  17. import Data.Traversable (Traversable(..))
  18. import GHC.Exts (IsList(..), IsString(..))
  19. -- | All S-Expressions can be understood as a sequence
  20. -- of @cons@ cells (represented here by 'SCons'), the
  21. -- empty list @nil@ (represented by 'SNil') or an
  22. -- @atom@.
  23. data SExpr atom
  24. = SCons (SExpr atom) (SExpr atom)
  25. | SAtom atom
  26. | SNil
  27. deriving (Eq, Show, Read, Functor, Data)
  28. instance IsString atom => IsString (SExpr atom) where
  29. fromString = SAtom . fromString
  30. instance IsList (SExpr atom) where
  31. type Item (SExpr atom) = SExpr atom
  32. fromList = foldr SCons SNil
  33. toList = go
  34. where go (SCons x xs) = x : go xs
  35. go SNil = []
  36. go (SAtom {}) = error "Unable to turn atom into list"
  37. instance Foldable SExpr where
  38. foldMap _ SNil = mempty
  39. foldMap f (SAtom a) = f a
  40. foldMap f (SCons x y) = foldMap f x <> foldMap f y
  41. instance Traversable SExpr where
  42. traverse f SNil = pure SNil
  43. traverse f (SAtom a) = SAtom <$> f a
  44. traverse f (SCons x y) = SCons <$> traverse f x <*> traverse f y
  45. -- | Sometimes the cons-based interface is too low
  46. -- level, and we'd rather have the lists themselves
  47. -- exposed. In this case, we have 'RSList' to
  48. -- represent a well-formed cons list, and 'RSDotted'
  49. -- to represent an improper list of the form
  50. -- @(a b c . d)@. This representation is based on
  51. -- the shape of the parsed S-Expression, and not on
  52. -- how it was represented, so @(a . (b))@ is going to
  53. -- be represented as @RSList[RSAtom a, RSAtom b]@
  54. -- despite having been originally represented as a
  55. -- dotted list.
  56. data RichSExpr atom
  57. = RSList [RichSExpr atom]
  58. | RSDotted [RichSExpr atom] atom
  59. | RSAtom atom
  60. deriving (Eq, Show, Read, Functor)
  61. instance IsString atom => IsString (RichSExpr atom) where
  62. fromString = RSAtom . fromString
  63. instance IsList (RichSExpr atom) where
  64. type Item (RichSExpr atom) = RichSExpr atom
  65. fromList = RSList
  66. toList (RSList xs) = xs
  67. toList (RSDotted {}) = error "Unable to turn dotted list into haskell list"
  68. toList (RSAtom {}) = error "Unable to turn atom into Haskell list"
  69. -- | It should always be true that
  70. --
  71. -- > fromRich (toRich x) == x
  72. --
  73. -- and that
  74. --
  75. -- > toRich (fromRich x) == x
  76. toRich :: SExpr atom -> RichSExpr atom
  77. toRich (SAtom a) = RSAtom a
  78. toRich (SCons x xs) = go xs (toRich x:)
  79. where go (SAtom a) rs = RSDotted (rs []) a
  80. go SNil rs = RSList (rs [])
  81. go (SCons x xs) rs = go xs (rs . (toRich x:))
  82. -- | This follows the same laws as 'toRich'.
  83. fromRich :: RichSExpr atom -> SExpr atom
  84. fromRich (RSAtom a) = SAtom a
  85. fromRich (RSList xs) = foldr SCons SNil (map fromRich xs)
  86. fromRich (RSDotted xs x) = foldr SCons (SAtom x) (map fromRich xs)
  87. instance Foldable RichSExpr where
  88. foldMap f (RSAtom a) = f a
  89. foldMap f (RSList xs) = mconcat $ map (foldMap f) xs
  90. foldMap f (RSDotted xs y) = mconcat (map (foldMap f) xs) <> f y
  91. instance Traversable RichSExpr where
  92. traverse f (RSAtom a) = RSAtom <$> f a
  93. traverse f (RSList xs) = RSList <$> sequenceA (map (traverse f) xs)
  94. traverse f (RSDotted xs y) = RSDotted <$> sequenceA (map (traverse f) xs)
  95. <*> f y
  96. -- | A well-formed s-expression is one which does not
  97. -- contain any dotted lists. This means that not
  98. -- every value of @SExpr a@ can be converted to a
  99. -- @WellFormedSExpr a@, although the opposite is
  100. -- fine.
  101. data WellFormedSExpr atom
  102. = WFSList [WellFormedSExpr atom]
  103. | WFSAtom atom
  104. deriving (Eq, Show, Read, Functor)
  105. instance IsList (WellFormedSExpr atom) where
  106. type Item (WellFormedSExpr atom) = WellFormedSExpr atom
  107. fromList = WFSList
  108. toList (WFSList xs) = xs
  109. toList (WFSAtom {}) = error "Unable to turn atom into Haskell list"
  110. instance IsString atom => IsString (WellFormedSExpr atom) where
  111. fromString = WFSAtom . fromString
  112. instance Foldable WellFormedSExpr where
  113. foldMap f (WFSAtom a) = f a
  114. foldMap f (WFSList xs) = mconcat $ map (foldMap f) xs
  115. instance Traversable WellFormedSExpr where
  116. traverse f (WFSAtom a) = WFSAtom <$> f a
  117. traverse f (WFSList xs) = WFSList <$> sequenceA (map (traverse f) xs)
  118. -- | This will be @Nothing@ if the argument contains an
  119. -- improper list. It should hold that
  120. --
  121. -- > toWellFormed (fromWellFormed x) == Right x
  122. --
  123. -- and also (more tediously) that
  124. --
  125. -- > case toWellFormed x of
  126. -- > Left _ -> True
  127. -- > Right y -> x == fromWellFormed y
  128. toWellFormed :: SExpr atom -> Either String (WellFormedSExpr atom)
  129. toWellFormed SNil = return (WFSList [])
  130. toWellFormed (SAtom a) = return (WFSAtom a)
  131. toWellFormed (SCons x xs) = do
  132. x' <- toWellFormed x
  133. go xs (x':)
  134. where go (SAtom a) rs = Left "Found atom in cdr position"
  135. go SNil rs = return (WFSList (rs []))
  136. go (SCons x xs) rs = do
  137. x' <- toWellFormed x
  138. go xs (rs . (x':))
  139. -- | Convert a WellFormedSExpr back into a SExpr.
  140. fromWellFormed :: WellFormedSExpr atom -> SExpr atom
  141. fromWellFormed (WFSAtom a) = SAtom a
  142. fromWellFormed (WFSList xs) =
  143. foldr SCons SNil (map fromWellFormed xs)