123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- {-# LANGUAGE DeriveDataTypeable #-}
- {-# LANGUAGE DeriveFoldable #-}
- {-# LANGUAGE DeriveFunctor #-}
- {-# LANGUAGE DeriveTraversable #-}
- {-# LANGUAGE TypeFamilies #-}
- module Data.SCargot.Repr
- ( -- $reprs
- -- * Elementary SExpr representation
- SExpr(..)
- -- * Rich SExpr representation
- , RichSExpr(..)
- , toRich
- , fromRich
- -- * Well-Formed SExpr representation
- , WellFormedSExpr(..)
- , toWellFormed
- , fromWellFormed
- ) where
- import Data.Data (Data)
- import Data.Foldable (Foldable(..))
- import Data.Traversable (Traversable(..))
- import Data.Typeable (Typeable)
- import GHC.Exts (IsList(..), IsString(..))
- #if !MIN_VERSION_base(4,8,0)
- import Prelude hiding (foldr)
- #endif
- -- | All S-Expressions can be understood as a sequence
- -- of @cons@ cells (represented here by 'SCons'), the
- -- empty list @nil@ (represented by 'SNil') or an
- -- @atom@.
- data SExpr atom
- = SCons (SExpr atom) (SExpr atom)
- | SAtom atom
- | SNil
- deriving (Eq, Show, Read, Functor, Data, Typeable, Foldable, Traversable)
- instance IsString atom => IsString (SExpr atom) where
- fromString = SAtom . fromString
- instance IsList (SExpr atom) where
- type Item (SExpr atom) = SExpr atom
- fromList = foldr SCons SNil
- toList = go
- where go (SCons x xs) = x : go xs
- go SNil = []
- go (SAtom {}) = error "Unable to turn atom into list"
- -- | Sometimes the cons-based interface is too low
- -- level, and we'd rather have the lists themselves
- -- exposed. In this case, we have 'RSList' to
- -- represent a well-formed cons list, and 'RSDotted'
- -- to represent an improper list of the form
- -- @(a b c . d)@. This representation is based on
- -- the structure of the parsed S-Expression, and not on
- -- how it was originally represented: thus, @(a . (b))@ is going to
- -- be represented as @RSList[RSAtom a, RSAtom b]@
- -- despite having been originally represented as a
- -- dotted list.
- data RichSExpr atom
- = RSList [RichSExpr atom]
- | RSDotted [RichSExpr atom] atom
- | RSAtom atom
- deriving (Eq, Show, Read, Functor, Data, Typeable, Foldable, Traversable)
- instance IsString atom => IsString (RichSExpr atom) where
- fromString = RSAtom . fromString
- instance IsList (RichSExpr atom) where
- type Item (RichSExpr atom) = RichSExpr atom
- fromList = RSList
- toList (RSList xs) = xs
- toList (RSDotted {}) = error "Unable to turn dotted list into haskell list"
- toList (RSAtom {}) = error "Unable to turn atom into Haskell list"
- -- | It should always be true that
- --
- -- > fromRich (toRich x) == x
- --
- -- and that
- --
- -- > toRich (fromRich x) == x
- toRich :: SExpr atom -> RichSExpr atom
- toRich (SAtom a) = RSAtom a
- toRich (SCons x xs) = go xs (toRich x:)
- where go (SAtom a) rs = RSDotted (rs []) a
- go SNil rs = RSList (rs [])
- go (SCons y ys) rs = go ys (rs . (toRich y:))
- toRich SNil = RSList []
- -- | This follows the same laws as 'toRich'.
- fromRich :: RichSExpr atom -> SExpr atom
- fromRich (RSAtom a) = SAtom a
- fromRich (RSList xs) = foldr SCons SNil (map fromRich xs)
- fromRich (RSDotted xs x) = foldr SCons (SAtom x) (map fromRich xs)
- -- | A well-formed s-expression is one which does not
- -- contain any dotted lists. This means that not
- -- every value of @SExpr a@ can be converted to a
- -- @WellFormedSExpr a@, although the opposite is
- -- fine.
- data WellFormedSExpr atom
- = WFSList [WellFormedSExpr atom]
- | WFSAtom atom
- deriving (Eq, Show, Read, Functor, Data, Typeable, Foldable, Traversable)
- instance IsList (WellFormedSExpr atom) where
- type Item (WellFormedSExpr atom) = WellFormedSExpr atom
- fromList = WFSList
- toList (WFSList xs) = xs
- toList (WFSAtom {}) = error "Unable to turn atom into Haskell list"
- instance IsString atom => IsString (WellFormedSExpr atom) where
- fromString = WFSAtom . fromString
- -- | This will be @Nothing@ if the argument contains an
- -- improper list. It should hold that
- --
- -- > toWellFormed (fromWellFormed x) == Right x
- --
- -- and also (more tediously) that
- --
- -- > case toWellFormed x of
- -- > Left _ -> True
- -- > Right y -> x == fromWellFormed y
- toWellFormed :: SExpr atom -> Either String (WellFormedSExpr atom)
- toWellFormed SNil = return (WFSList [])
- toWellFormed (SAtom a) = return (WFSAtom a)
- toWellFormed (SCons x xs) = do
- x' <- toWellFormed x
- go xs (x':)
- where go (SAtom _) _ = Left "Found atom in cdr position"
- go SNil rs = return (WFSList (rs []))
- go (SCons y ys) rs = do
- y' <- toWellFormed y
- go ys (rs . (y':))
- -- | Convert a WellFormedSExpr back into a SExpr.
- fromWellFormed :: WellFormedSExpr atom -> SExpr atom
- fromWellFormed (WFSAtom a) = SAtom a
- fromWellFormed (WFSList xs) =
- foldr SCons SNil (map fromWellFormed xs)
- {- $reprs
- This module contains several different representations for
- s-expressions. The s-cargot library underlying uses the
- 'SExpr' type as its representation type, which is a binary
- tree representation with an arbitrary type for its leaves.
- This type is not always convenient to manipulate in Haskell
- code, this module defines two alternate representations
- which turn a sequence of nested right-branching cons pairs
- into Haskell lists: that is to say, they transform between
- @
- SCons a (SCons b (SCons c SNil)) \<=\> RSList [a, b, c]
- @
- These two types differ in how they handle non-well-formed
- lists, i.e. lists that end with an atom. The 'RichSExpr'
- format handles this with a special constructor for lists
- that end in an atom:
- @
- SCons a (SCons b (SAtom c)) \<=\> RSDotted [a, b] c
- @
- On the other hand, the 'WellFormedSExpr' type elects
- not to handle this case. This is unusual for Lisp source code,
- but is a reasonable choice for configuration or data
- storage formats that use s-expressions, where
- non-well-formed lists would be an unnecessary
- complication.
- To make working with these types less verbose, there are other
- modules that export pattern aliases and helper functions: these
- can be found at "Data.SCargot.Repr.Basic",
- "Data.SCargot.Repr.Rich", and "Data.SCargot.Repr.WellFormed".
- -}
|