Repr.hs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. {-# LANGUAGE DeriveFunctor #-}
  2. module Data.SCargot.Repr
  3. ( -- * Elementary SExpr representation
  4. SExpr(..)
  5. -- * Rich SExpr representation
  6. , RichSExpr(..)
  7. , toRich
  8. , fromRich
  9. -- * Well-Formed SExpr representation
  10. , WellFormedSExpr(..)
  11. , toWellFormed
  12. , fromWellFormed
  13. ) where
  14. import Data.String (IsString(..))
  15. -- | All S-Expressions can be understood as a sequence
  16. -- of @cons@ cells (represented here by 'SCons'), the
  17. -- empty list @nil@ (represented by 'SNil') or an
  18. -- @atom@.
  19. data SExpr atom
  20. = SCons (SExpr atom) (SExpr atom)
  21. | SAtom atom
  22. | SNil
  23. deriving (Eq, Show, Read, Functor)
  24. instance IsString atom => IsString (SExpr atom) where
  25. fromString = SAtom . fromString
  26. -- | Sometimes, the cons-based interface is too low
  27. -- level, and we'd rather have the lists themselves
  28. -- exposed. In this case, we have 'RSList' to
  29. -- represent a well-formed cons list, and 'RSDotted'
  30. -- to represent an improper list of the form
  31. -- @(a b c . d)@. This representation is based on
  32. -- the shape of the parsed S-Expression, and not on
  33. -- how it was represented, so @(a . (b))@ is going to
  34. -- be represented as @RSList[RSAtom a, RSAtom b]@
  35. -- despite having been originally represented as a
  36. -- dotted list.
  37. data RichSExpr atom
  38. = RSList [RichSExpr atom]
  39. | RSDotted [RichSExpr atom] atom
  40. | RSAtom atom
  41. deriving (Eq, Show, Read, Functor)
  42. instance IsString atom => IsString (RichSExpr atom) where
  43. fromString = RSAtom . fromString
  44. -- | It should always be true that
  45. --
  46. -- > fromRich (toRich x) == x
  47. --
  48. -- and that
  49. --
  50. -- > toRich (fromRich x) == x
  51. toRich :: SExpr atom -> RichSExpr atom
  52. toRich (SAtom a) = RSAtom a
  53. toRich (SCons x xs) = go xs (toRich x:)
  54. where go (SAtom a) rs = RSDotted (rs []) a
  55. go SNil rs = RSList (rs [])
  56. go (SCons x xs) rs = go xs (rs . (toRich x:))
  57. -- | This follows the same laws as 'toRich'.
  58. fromRich :: RichSExpr atom -> SExpr atom
  59. fromRich (RSAtom a) = SAtom a
  60. fromRich (RSList xs) = foldr SCons SNil (map fromRich xs)
  61. fromRich (RSDotted xs x) = foldr SCons (SAtom x) (map fromRich xs)
  62. -- | A well-formed s-expression is one which does not
  63. -- contain any dotted lists. This means that not
  64. -- every value of @SExpr a@ can be converted to a
  65. -- @WellFormedSExpr a@, although the opposite is
  66. -- fine.
  67. data WellFormedSExpr atom
  68. = WFSList [WellFormedSExpr atom]
  69. | WFSAtom atom
  70. deriving (Eq, Show, Read, Functor)
  71. instance IsString atom => IsString (WellFormedSExpr atom) where
  72. fromString = WFSAtom . fromString
  73. -- | This will be @Nothing@ if the argument contains an
  74. -- improper list. It should hold that
  75. --
  76. -- > toWellFormed (fromWellFormed x) == Right x
  77. --
  78. -- and also (more tediously) that
  79. --
  80. -- > case toWellFormed x of
  81. -- > Left _ -> True
  82. -- > Right y -> x == fromWellFormed y
  83. toWellFormed :: SExpr atom -> Either String (WellFormedSExpr atom)
  84. toWellFormed SNil = return (WFSList [])
  85. toWellFormed (SAtom a) = return (WFSAtom a)
  86. toWellFormed (SCons x xs) = do
  87. x' <- toWellFormed x
  88. go xs (x':)
  89. where go (SAtom a) rs = Left "Found atom in cdr position"
  90. go SNil rs = return (WFSList (rs []))
  91. go (SCons x xs) rs = do
  92. x' <- toWellFormed x
  93. go xs (rs . (x':))
  94. -- | Convert a WellFormedSExpr back into a SExpr.
  95. fromWellFormed :: WellFormedSExpr atom -> SExpr atom
  96. fromWellFormed (WFSAtom a) = SAtom a
  97. fromWellFormed (WFSList xs) =
  98. foldr SCons SNil (map fromWellFormed xs)