diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Sam Boosalis
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/Main.hs b/Main.hs
new file mode 100644
--- /dev/null
+++ b/Main.hs
@@ -0,0 +1,1 @@
+import Data.Sexp.Main
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/s-expression.cabal b/s-expression.cabal
new file mode 100644
--- /dev/null
+++ b/s-expression.cabal
@@ -0,0 +1,88 @@
+name: s-expression
+version: 0.0.0
+cabal-version: >=1.10
+build-type: Simple
+license: MIT
+license-file: LICENSE
+copyright: Copyright (C) 2015 Spiros M. Boosalis
+maintainer: samboosalis@gmail.com
+stability: experimental
+homepage: https://github.com/sboosali/s-expression#readme
+bug-reports: https://github.com/sboosali/s-expression/issues
+synopsis: simple general-purpose s-expressions 
+description: 
+ this package provides general-purpose functionality for manipulating s-expressions. like:
+ . 
+ * a @Functor@ instance that transforms the atoms
+ . 
+ * a @Monad@ instance that "expands" atoms into s-expressions
+ . 
+ * a @Foldable@ instance that enumerates the atoms (leaves)
+ . 
+ * @IsList@ and @IsString@ instances for literal syntax 
+ . 
+ * 
+ . 
+ * 
+ . 
+ * 
+ . 
+ the core type is:
+ . 
+ @
+ data <https://hackage.haskell.org/package/s-expression/docs//Data-Sexp.html Sexp> f a
+  = Atom a 
+  | List   [Sexp f a]
+  | Sexp f [Sexp f a]
+ @
+ .
+ which lets you provide your own custom function name that interprets its arguments.
+ . 
+ e.g. TODO  
+ . 
+ for efficient parsing/printing, use:  
+ . 
+ * https://hackage.haskell.org/package/sexp
+ . 
+ * https://hackage.haskell.org/package/atto-lisp
+ . 
+
+category: Data 
+author: Spiros Boosalis
+tested-with: GHC ==7.10.1
+
+source-repository head
+    type: git
+    location: https://github.com/sboosali/s-expression
+
+library
+
+ exposed-modules:
+  Data.Sexp 
+  Data.Sexp.Example 
+  Data.Sexp.Main 
+
+ build-depends:
+    base >=4.8 && <5.0
+
+  -- cabal sandbox add-source ... 
+  , derive-monoid >=0.0.1  
+
+  , lens 
+  , semigroups
+
+ default-language: Haskell2010
+ hs-source-dirs: sources
+ ghc-options: -Wall
+ default-extensions: AutoDeriveTypeable
+
+
+executable example-s-expressions
+ main-is: Main.hs
+ build-depends:
+    base
+  , s-expression
+ default-language: Haskell2010
+ hs-source-dirs: .
+ ghc-options: -Wall
+
diff --git a/sources/Data/Sexp.hs b/sources/Data/Sexp.hs
new file mode 100644
--- /dev/null
+++ b/sources/Data/Sexp.hs
@@ -0,0 +1,330 @@
+{-# LANGUAGE AutoDeriveTypeable, DeriveDataTypeable, DeriveGeneric, DeriveAnyClass, DeriveFunctor, DeriveFoldable, DeriveTraversable  #-}
+{-# LANGUAGE TemplateHaskell, LambdaCase, TypeFamilies #-}
+module Data.Sexp where
+
+import Derive.List (deriveList) 
+import Control.Lens (Plated (..)) 
+
+import Data.Foldable  (Foldable (..))
+import Data.Data (Data) 
+import GHC.Generics (Generic) 
+import GHC.Exts       (IsString (..))
+import Data.Void (Void) 
+
+
+{- | a heterogenous list.
+
+a <http://en.wikipedia.org/wiki/Common_Lisp#The_function_namespace 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 'Monad'ic 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"]]]
+
+-}
+data Sexp f a
+ = Atom a 
+ | List   [Sexp f a]
+ | Sexp f [Sexp f a]
+ deriving (Show,Read,Eq,Ord,Functor,Foldable,Traversable,Data,Generic)
+
+{-| 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).  
+
+-}
+type Sexp_ = Sexp Void 
+
+{-| 
+
+@
+data ByteSexp
+ = Atom ByteString
+ | List [ByteSexp]
+
+bytesexp2sexp :: ByteSexp -> 'Sexp_' ByteString
+bytesexp2sexp = 'toSexp' $ \case
+ Atom s  -> Left  s 
+ List es -> Right es 
+@
+
+-}
+toSexp :: (r -> Either a [r]) -> (r -> Sexp_ a)  
+toSexp f = go
+ where 
+ go r = case f r of 
+  Left  a  -> Atom a 
+  Right rs -> List (map go rs) 
+
+-- | default instance via the 'Monad' subclass.
+instance Applicative (Sexp f) where
+ pure = return 
+ (<*>) f x = f >>= (\g -> x >>= (return.g))
+
+{- |
+
+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
+    @
+
+-}
+instance Monad (Sexp f) where
+ return = pure
+ (>>=)  = bindSexp
+-- TODO laws, verified as @QuickCheck@ properties:
+
+instance Plated (Sexp f a) where
+ plate f = \case
+  Atom a    -> Atom   <$> pure a
+  List   ps -> List   <$> traverse f ps
+  Sexp g ps -> Sexp g <$> traverse f ps
+
+{-| 
+
+>>> :set -XOverloadedStrings  
+>>> "x" :: Sexp f String
+Atom "x" 
+
+-}
+instance (IsString a) => IsString (Sexp f a) where
+ fromString = Atom . fromString
+
+{-| @pureSexp = 'Atom'@
+-}
+pureSexp :: a -> Sexp f a
+pureSexp = Atom
+{-# INLINE pureSexp #-}
+
+bindSexp :: Sexp f a -> (a -> Sexp f b) -> Sexp f b
+bindSexp s f = (joinSexp . fmap f) s
+{-# INLINE bindSexp #-}
+
+{-| 
+
+-}
+joinSexp :: Sexp f (Sexp f a) -> Sexp f a
+joinSexp = \case
+ Atom     e -> e
+ List   ess -> List   (joinSexp <$> ess)
+ Sexp f ess -> Sexp f (joinSexp <$> ess)
+{-# INLINEABLE joinSexp #-} -- to hit the Atom I hope.
+
+deriveList ''Sexp 'List 
+
+{-| refines any Sexp to a list, which can be given to the 'List'. -}
+toSexpList :: Sexp f a -> [Sexp f a]
+
+{-| >>> appendSexp (Atom "f") (List [Atom "x"])
+List [Atom "f",Atom "x"]
+-}
+appendSexp :: Sexp f a -> Sexp f a -> Sexp f a
+
+{-| @emptySexp = 'List' []@ -}
+emptySexp :: Sexp f a
+
+
+{-| fold over an sexp. 
+
+i.e. strictly evaluate a sexp ("all the way") to an atom, within any monadic context.
+
+-}
+evalSexp :: (Monad m) => ([a] -> m a) -> ([a] -> g -> m a) -> Sexp g a -> m a
+evalSexp list apply = \case
+ Atom a    -> pure a
+ List   es -> list           =<< traverse go es
+ Sexp g es -> (flip apply) g =<< traverse go es
+ where
+ go = evalSexp list apply
+
+{-| 
+
+>>> 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')@ 
+
+-}
+evalSplatSexp :: (Monad m, Monoid b) => (b -> g -> m b) -> (Sexp g b -> m b)
+evalSplatSexp apply = evalSexp (pure.fold) (apply.fold)
+{-# INLINE evalSplatSexp #-}
+
+{-| 
+
+when a Sexp\'s atoms are 'Monoid'al ("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.
+
+-}
+splatSexpList :: (Applicative m, Monoid b) => (Sexp g b -> m b) -> [Sexp g b] -> m b
+splatSexpList eval = fmap fold . traverse eval 
+{-# INLINE splatSexpList #-}
+
+{-| inject a list of atoms.  
+
+>>> listSexp [1,2,3]
+List [Atom 1,Atom 2,Atom 3]
+
+-}
+listSexp :: [a] -> Sexp f a
+listSexp = List . map Atom 
+{-# INLINE listSexp #-}
+
+-- data SexpF f a r
+--  = AtomF a
+--  | FuncF (f r) 
+--  | ListF [r]
+--  deriving (Show,Read,Eq,Ord,Functor,Data,Generic)
+
+-- type Sexp' a = Fix (SexpF a)
+
+{- helper when converting from other sexp types, like from a parsing library. 
+
+@Either Bytestring [Bytestring]@ 
+
+is isomorphic to: 
+
+e.g. the @atto-lisp@ package defines: 
+
+@
+data Lisp
+  = Symbol Text   -- ^ A symbol (including keyword)
+  | String Text   -- ^ A string.
+  | Number Number   -- ^ A number
+  | List [Lisp]     -- ^ A proper list: @(foo x 42)@
+  | DotList [Lisp] Lisp  -- ^ A list with a non-nil tail: @(foo x
+                         -- . 42)@.  The list argument must be
+                         -- non-empty and the tail must be non-'nil'.
+@ 
+
+we can define: 
+
+@
+type AttoLispSexp = Sexp AttoLispFunc AttoLispAtom
+data AttoLispAtom = SymbolAtom Text | StringAtom Text | NumberAtom Number 
+TODO data AttoLispFunc r = DotListFunc [r] r 
+@
+
+
+-}
+-- fromSexp ::  -> 
+-- fromSexp = 
+
+-- toSexp ::  -> 
+-- toSexp = 
+
diff --git a/sources/Data/Sexp/Example.hs b/sources/Data/Sexp/Example.hs
new file mode 100644
--- /dev/null
+++ b/sources/Data/Sexp/Example.hs
@@ -0,0 +1,19 @@
+{-# LANGUAGE OverloadedLists, OverloadedStrings #-}
+{-| (see source) 
+
+-}
+module Data.Sexp.Example where 
+import Data.Sexp 
+
+
+exampleSexp :: Sexp () String
+exampleSexp = ["f", "x", ["g", "y"], "z"]
+
+-- type ElispSexp = Sexp ElispFunc ElispAtom
+
+-- data ElispAtom
+--  = 
+
+-- data ElispFunc
+--  = 
+
diff --git a/sources/Data/Sexp/Main.hs b/sources/Data/Sexp/Main.hs
new file mode 100644
--- /dev/null
+++ b/sources/Data/Sexp/Main.hs
@@ -0,0 +1,15 @@
+{-# LANGUAGE LambdaCase #-}
+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
+module Data.Sexp.Main where 
+import Data.Sexp.Example 
+import Data.Foldable  (Foldable (..))
+
+import           System.Environment             (getArgs)
+
+
+main = mainWith =<< getArgs
+
+mainWith = \case
+ _ -> do 
+  print$ exampleSexp 
+  print$ toList exampleSexp
