s-expression-0.0.0: simple general-purpose s-expressions

Safe HaskellNone
LanguageHaskell2010

Data.Sexp

Synopsis

Documentation

data Sexp f a Source #

a heterogenous list.

a Lisp-2 S-expression, where:

  • f is the function namespace
  • a is the atom namespace

you could define type Lisp1 a = Sexp a a. with some caveats:

  • f is ignored by Monadic methods like joinSexp
  • plate doesn't reach the f, even when f ~ a, as the Plated instance is manual, not automatic via Data.

the List case is just a specialized Sexp (), but easier to work with than:

  • Sexp (Maybe f) [Sexp f a] (where Nothing would represent List)
  • forcing each concrete f to hold a unit case (which would represent List)

examples:

>>> 'toList' (List [Atom "f",Atom "x",List [Atom "g",Atom "y"],Atom "z"])
["f","x","g","y","z"]
>>> :{
let doubleSexp e = do
                    x <- e
                    listSexp [x,x]
:} 
>>> doubleSexp (List [Atom "f", Sexp () [Atom "a", Atom "b"]])
List [List [Atom "f",Atom "f"],Sexp () [List [Atom "a",Atom "a"],List [Atom "b",Atom "b"]]]

Constructors

Atom a 
List [Sexp f a] 
Sexp f [Sexp f a] 

Instances

Monad (Sexp f) Source #

definitions:

 return = pureSexp
 '(>>=)' = bindSexp

proofs of laws:

  • left-inverse(1): join . return = id

    join (return m)
    joinSexp (pureSexp m)
    joinSexp (Atom m)
    m
    
  • left-inverse(2): join . fmap return = id

    (the Sexp case is elided, the steps being identical to the List case)

    join (fmap return m)
    joinSexp (fmap pureSexp m)
    joinSexp (fmap Atom m)
    -- case analysis 
    case m of
     Atom x ->
      joinSexp (Atom (Atom x)) 
      -- by definition of joinSexp
      Atom x
     List ms ->
      joinSexp (List (fmap (fmap Atom) ms)
      -- by definition of joinSexp
      List (fmap joinSexp (fmap (fmap Atom) ms))
      -- functor composition 
      List (fmap (joinSexp . fmap Atom) ms)
      List (fmap (join . fmap return) ms)
      -- by induction
      List (fmap id ms)
      -- functor identity 
      List ms
     -- both cases are identity 
    m
    

    where:

    fmap f = case
     Atom x  -> f x 
     List ms -> List (fmap (fmap f) ms)
    
    join = case
     Atom x  -> x 
     List ms -> List (fmap joinSexp ms)
    
  • associativity(3): join . join = join . fmap join

    TODO
    

Methods

(>>=) :: Sexp f a -> (a -> Sexp f b) -> Sexp f b #

(>>) :: Sexp f a -> Sexp f b -> Sexp f b #

return :: a -> Sexp f a #

fail :: String -> Sexp f a #

Functor (Sexp f) Source # 

Methods

fmap :: (a -> b) -> Sexp f a -> Sexp f b #

(<$) :: a -> Sexp f b -> Sexp f a #

Applicative (Sexp f) Source #

default instance via the Monad subclass.

Methods

pure :: a -> Sexp f a #

(<*>) :: Sexp f (a -> b) -> Sexp f a -> Sexp f b #

(*>) :: Sexp f a -> Sexp f b -> Sexp f b #

(<*) :: Sexp f a -> Sexp f b -> Sexp f a #

Foldable (Sexp f) Source # 

Methods

fold :: Monoid m => Sexp f m -> m #

foldMap :: Monoid m => (a -> m) -> Sexp f a -> m #

foldr :: (a -> b -> b) -> b -> Sexp f a -> b #

foldr' :: (a -> b -> b) -> b -> Sexp f a -> b #

foldl :: (b -> a -> b) -> b -> Sexp f a -> b #

foldl' :: (b -> a -> b) -> b -> Sexp f a -> b #

foldr1 :: (a -> a -> a) -> Sexp f a -> a #

foldl1 :: (a -> a -> a) -> Sexp f a -> a #

toList :: Sexp f a -> [a] #

null :: Sexp f a -> Bool #

length :: Sexp f a -> Int #

elem :: Eq a => a -> Sexp f a -> Bool #

maximum :: Ord a => Sexp f a -> a #

minimum :: Ord a => Sexp f a -> a #

sum :: Num a => Sexp f a -> a #

product :: Num a => Sexp f a -> a #

Traversable (Sexp f) Source # 

Methods

traverse :: Applicative f => (a -> f b) -> Sexp f a -> f (Sexp f b) #

sequenceA :: Applicative f => Sexp f (f a) -> f (Sexp f a) #

mapM :: Monad m => (a -> m b) -> Sexp f a -> m (Sexp f b) #

sequence :: Monad m => Sexp f (m a) -> m (Sexp f a) #

IsList (Sexp a b) Source # 

Associated Types

type Item (Sexp a b) :: * #

Methods

fromList :: [Item (Sexp a b)] -> Sexp a b #

fromListN :: Int -> [Item (Sexp a b)] -> Sexp a b #

toList :: Sexp a b -> [Item (Sexp a b)] #

(Eq f, Eq a) => Eq (Sexp f a) Source # 

Methods

(==) :: Sexp f a -> Sexp f a -> Bool #

(/=) :: Sexp f a -> Sexp f a -> Bool #

(Data a, Data f) => Data (Sexp f a) Source # 

Methods

gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> Sexp f a -> c (Sexp f a) #

gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c (Sexp f a) #

toConstr :: Sexp f a -> Constr #

dataTypeOf :: Sexp f a -> DataType #

dataCast1 :: Typeable (* -> *) t => (forall d. Data d => c (t d)) -> Maybe (c (Sexp f a)) #

dataCast2 :: Typeable (* -> * -> *) t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (Sexp f a)) #

gmapT :: (forall b. Data b => b -> b) -> Sexp f a -> Sexp f a #

gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Sexp f a -> r #

gmapQr :: (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Sexp f a -> r #

gmapQ :: (forall d. Data d => d -> u) -> Sexp f a -> [u] #

gmapQi :: Int -> (forall d. Data d => d -> u) -> Sexp f a -> u #

gmapM :: Monad m => (forall d. Data d => d -> m d) -> Sexp f a -> m (Sexp f a) #

gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> Sexp f a -> m (Sexp f a) #

gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> Sexp f a -> m (Sexp f a) #

(Ord f, Ord a) => Ord (Sexp f a) Source # 

Methods

compare :: Sexp f a -> Sexp f a -> Ordering #

(<) :: Sexp f a -> Sexp f a -> Bool #

(<=) :: Sexp f a -> Sexp f a -> Bool #

(>) :: Sexp f a -> Sexp f a -> Bool #

(>=) :: Sexp f a -> Sexp f a -> Bool #

max :: Sexp f a -> Sexp f a -> Sexp f a #

min :: Sexp f a -> Sexp f a -> Sexp f a #

(Read f, Read a) => Read (Sexp f a) Source # 

Methods

readsPrec :: Int -> ReadS (Sexp f a) #

readList :: ReadS [Sexp f a] #

readPrec :: ReadPrec (Sexp f a) #

readListPrec :: ReadPrec [Sexp f a] #

(Show f, Show a) => Show (Sexp f a) Source # 

Methods

showsPrec :: Int -> Sexp f a -> ShowS #

show :: Sexp f a -> String #

showList :: [Sexp f a] -> ShowS #

IsString a => IsString (Sexp f a) Source #
>>> :set -XOverloadedStrings
>>> "x" :: Sexp f String
Atom "x" 

Methods

fromString :: String -> Sexp f a #

Generic (Sexp f a) Source # 

Associated Types

type Rep (Sexp f a) :: * -> * #

Methods

from :: Sexp f a -> Rep (Sexp f a) x #

to :: Rep (Sexp f a) x -> Sexp f a #

Semigroup (Sexp a b) Source # 

Methods

(<>) :: Sexp a b -> Sexp a b -> Sexp a b #

sconcat :: NonEmpty (Sexp a b) -> Sexp a b #

stimes :: Integral b => b -> Sexp a b -> Sexp a b #

Monoid (Sexp a b) Source # 

Methods

mempty :: Sexp a b #

mappend :: Sexp a b -> Sexp a b -> Sexp a b #

mconcat :: [Sexp a b] -> Sexp a b #

Plated (Sexp f a) Source # 

Methods

plate :: Traversal' (Sexp f a) (Sexp f a) #

type Rep (Sexp f a) Source # 
type Item (Sexp a b) Source # 
type Item (Sexp a b) = Sexp a b

type Sexp_ = Sexp Void Source #

isomorphic to:

data Sexp_ a
 = Atom_ a 
 | List_ [Sexp_ a]

when you only care about lists (e.g. to interface with other s-expression libraries).

toSexp :: (r -> Either a [r]) -> r -> Sexp_ a Source #

data ByteSexp
 = Atom ByteString
 | List [ByteSexp]

bytesexp2sexp :: ByteSexp -> Sexp_ ByteString
bytesexp2sexp = toSexp $ case
 Atom s  -> Left  s 
 List es -> Right es 

pureSexp :: a -> Sexp f a Source #

pureSexp = Atom

bindSexp :: Sexp f a -> (a -> Sexp f b) -> Sexp f b Source #

joinSexp :: Sexp f (Sexp f a) -> Sexp f a Source #

toSexpList :: Sexp f a -> [Sexp f a] Source #

refines any Sexp to a list, which can be given to the List.

appendSexp :: Sexp f a -> Sexp f a -> Sexp f a Source #

>>> appendSexp (Atom "f") (List [Atom "x"])
List [Atom "f",Atom "x"]

emptySexp :: Sexp f a Source #

emptySexp = List []

evalSexp :: Monad m => ([a] -> m a) -> ([a] -> g -> m a) -> Sexp g a -> m a Source #

fold over an sexp.

i.e. strictly evaluate a sexp ("all the way") to an atom, within any monadic context.

evalSplatSexp :: (Monad m, Monoid b) => (b -> g -> m b) -> Sexp g b -> m b Source #

>>> data ArithFunc = Add | Multiply | Negate deriving Show
>>> let badArith  = Sexp Negate [Atom 1, Atom 2, Atom 3] :: Sexp ArithFunc Integer
>>> let goodArith = Sexp Add [Sexp Multiply [], Sexp Negate [Atom (10::Integer)], Sexp Multiply [Atom 2, Atom 3, Atom 4]]
>>> :set -XLambdaCase
>>> :{
let evalArith = \case
                 Add      -> \case
                              xs    -> Just [sum xs]
                 Multiply -> \case
                              xs    -> Just [product xs]
                 Negate   -> \case
                              [x]   -> Just [negate x] 
                              _     -> Nothing 
:}
>>> evalSplatSexp (flip evalArith) (fmap (:[]) badArith)  -- wrong arity
Nothing 
>>> evalSplatSexp (flip evalArith) (fmap (:[]) goodArith) -- (+ (*) (- 10) (* 2 3 4))
Just [15] 

specializing, as above, (m ~ Maybe), (b ~ [Integer]), (g ~ ArithFunc):

evalSplatSexp :: ([Integer] -> ArithFunc -> Maybe [Integer]) -> (Sexp ArithFunc [Integer] -> Maybe [Integer])
evalSplatSexp apply = evalSexp ('pure'.'fold') (apply.fold)

splatSexpList :: (Applicative m, Monoid b) => (Sexp g b -> m b) -> [Sexp g b] -> m b Source #

when a Sexp's atoms are Monoidal ("list-like"), after evaluating some expressions into atoms, we can "splat" them back together.

splatList takes:

  • an evaluator eval
  • and a list of s-expressions es to evaluate in sequence.

listSexp :: [a] -> Sexp f a Source #

inject a list of atoms.

>>> listSexp [1,2,3]
List [Atom 1,Atom 2,Atom 3]