diff --git a/Data/Combinator.hs b/Data/Combinator.hs
new file mode 100644
--- /dev/null
+++ b/Data/Combinator.hs
@@ -0,0 +1,161 @@
+{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable, TemplateHaskell #-}
+module Data.Combinator where
+
+import Prelude hiding (elem, notElem, foldl, foldr, length)
+import Data.Foldable
+import Control.Lens
+import Control.Applicative
+import Language.Haskell.TH
+import Language.Haskell.TH.Quote
+import Language.Haskell.TH.Lift
+import Data.Void
+import Text.Trifecta
+import Data.List (minimumBy)
+import Data.Function (on)
+import Data.Monoid
+
+infixl 9 :$
+
+data Expr e = Expr e :$ Expr e -- application
+            | I | K | S -- primitive combinators
+            | Var e -- external value
+              deriving (Show, Eq, Ord, Functor, Foldable, Traversable)
+
+deriveLift ''Expr
+
+instance Monad Expr where
+    return = Var
+    Var x >>= f = f x
+    (a :$ b) >>= f = (a >>= f) :$ (b >>= f)
+    I >>= _ = I
+    K >>= _ = K
+    S >>= _ = S
+
+-- Basic Functions
+-- | The 'length' function returns a length of an expression. 
+length :: Expr e -> Int
+length (f :$ g) = length f + length g + 1
+length _ = 1
+
+isPrim :: Expr e -> Bool
+isPrim S = True
+isPrim K = True
+isPrim I = True
+isPrim x = False
+
+subst :: Eq e => e -- free variable to search for
+    -> Expr e
+    -> Expr e -> Expr e
+subst v r (f :$ g) = subst v r f :$ subst v r g
+subst v r (Var v') | v == v' = r
+subst _ _ e = e
+
+-- | The 'bindee' function transforms an expression to a combinator which binds specified variable when it is applied.
+bindee :: Eq e => e -> Expr e -> Expr e
+-- refered to John Tromp "Binary Lambda Calculus and Combinatory Logic", 2011 (http://homepages.cwi.nl/~tromp/cl/LC.pdf section 3.2)
+bindee _ (S :$ K :$ _) = S :$ K
+bindee x f              | x `notElem` toList f = K :$ f
+bindee x (Var x')      | x == x' = I
+bindee x (f :$ Var x') | x `notElem` toList f && x == x' = f
+bindee x (Var y :$ f :$ Var z)
+    | x == y && x == z = bindee x $ S :$ S :$ K :$ Var x :$ f
+bindee x (f :$ (g :$ h))
+    | isPrim f && isPrim g = bindee x $ S :$ bindee x f :$ g :$ h
+bindee x ((f :$ g) :$ h)
+    | isPrim f && isPrim h = bindee x $ S :$ f :$ bindee x h :$ g
+bindee x ((f :$ g) :$ (h :$ g'))
+    | isPrim f && isPrim h && g == g' = bindee x $ S :$ f :$ h :$ g
+bindee x (f :$ g) = S :$ bindee x f :$ bindee x g
+
+apply :: Expr e -> Expr e -> Expr e
+apply I x = x
+apply (K :$ x) y = x
+apply (S :$ x :$ y) z = apply x z `apply` apply y z
+apply f g = f :$ g
+
+eval :: Expr e -> Expr e
+eval (f :$ g) = eval f `apply` eval g
+eval x = x
+
+unlambdaParser :: Parser (Expr String)
+unlambdaParser = char '`' *> ((:$) <$> unlambdaParser <*> unlambdaParser)
+    <|> char 's' *> pure S
+    <|> char 'k' *> pure K
+    <|> char 'i' *> pure I
+    <|> Var <$> (char '[' *> some (satisfy (/=']')) <* char ']')
+
+ccParser :: Parser (Expr String)
+ccParser = token $ foldl (:$) <$> term <*> many term where
+    term = token $ parens ccParser
+        <|> S <$ char 'S'
+        <|> K <$ char 'K'
+        <|> I <$ char 'I'
+        <|> lambda
+        <|> vacuous <$> stringLit
+        <|> vacuous <$> intLit
+        <|> Var <$> variable
+
+variable = token $ liftA2 (:) lower (many alphaNum)
+
+lambda :: Parser (Expr String)
+lambda = do
+    symbol "\\"
+    v <- variable
+    symbol "."
+    bindee v <$> ccParser
+
+stringLit :: Parser (Expr Void)
+stringLit = fmap (error "stringLit is buggy") $ bindee "C" <$> bindee "N"
+    <$> foldr (\x y -> Var "C" :$ x :$ y) (Var "N")
+    <$> map (encodeInt.fromEnum)
+    <$> (stringLiteral :: Parser String)
+
+intLit :: Parser (Expr Void)
+intLit = encodeInt <$> fromEnum <$> natural
+
+cc :: QuasiQuoter
+cc = QuasiQuoter { quoteExp = \s -> case parseString ccParser mempty s of
+    Success a -> lift a
+    Failure err -> fail $ show err
+    , quoteType = const $ fail "Unsupported"
+    , quoteDec = const $ fail "Unsupported"
+    , quotePat = const $ fail "Unsupported"  }
+
+showCC :: Expr String -> String
+showCC = snd . go False where
+    go _ I = (False, "I")
+    go _ K = (False, "K")
+    go _ S = (False, "S")
+    go _ (Var x) = (True, x)
+    go p (a :$ b)
+        | p = fmap (\x -> "(" ++ x ++ ")") s
+        | otherwise = s
+        where
+            s = case (go False a, go True b) of
+                ((True, l), (True, r)) -> (True, l ++ " " ++ r)
+                ((_, l), (_, r)) -> (False, l ++ r)
+
+ccExpression :: Prism' String (Expr String)
+ccExpression = prism' showCC (preview _Success . parseString (ccParser<*eof) mempty)
+
+churchNumeral :: Prism' (Expr a) Int
+churchNumeral = prism' encodeInt ((>>= decodeInt) . preview _Combinator)
+
+encodeInt :: Int -> Expr a
+encodeInt 0 = K :$ I
+encodeInt 1 = I
+encodeInt 2 = S :$ (S :$ (K :$ S) :$ K) :$ I
+encodeInt n
+    | mod n 2 == 0 = n'
+    | otherwise = S :$ (S :$ (K :$ S) :$ K) :$ n'
+    where
+        n' = S :$ (K :$ encodeInt 2) :$ encodeInt (div n 2)
+
+decodeInt :: Expr Void -> Maybe Int
+decodeInt e = go $ vacuous e `apply` Var True `apply` Var False where
+    go (Var True :$ x) = succ <$> go x
+    go (Var False) = Just 0
+    go _ = Nothing
+
+_Combinator :: Prism' (Expr a) (Expr Void)
+_Combinator = prism' vacuous (traverse (const Nothing)) where
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2013, Fumiaki Kinoshita
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Fumiaki Kinoshita nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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/combinator-interactive.cabal b/combinator-interactive.cabal
new file mode 100644
--- /dev/null
+++ b/combinator-interactive.cabal
@@ -0,0 +1,30 @@
+-- Initial combinator-interactive.cabal generated by cabal init.  For 
+-- further documentation, see http://haskell.org/cabal/users-guide/
+
+name:                combinator-interactive
+version:             0.1
+synopsis:            SKI Combinator interpreter
+description:         
+homepage:            https://github.com/fumieval/combinator-interactive
+license:             BSD3
+license-file:        LICENSE
+author:              Fumiaki Kinoshita
+maintainer:          fumiexcel@gmail.com
+copyright:           Copyright (c) 2013 Fumiaki Kinoshita
+category:            Language
+build-type:          Simple
+-- extra-source-files:  
+cabal-version:       >=1.10
+
+library
+  default-language:   Haskell2010
+  build-depends: base == 4.*, lens >=3.8 && <=4, template-haskell, th-lift, void, trifecta == 1.*
+  exposed-modules: Data.Combinator
+
+executable lazyi
+  main-is: main.hs
+  -- other-modules:       
+  other-extensions:    DeriveFunctor, DeriveFoldable, DeriveTraversable, TemplateHaskell
+  build-depends:       base == 4.*, lens >=3.8 && <=4, void, trifecta == 1.*, template-haskell, th-lift, combinator-interactive, containers, mtl == 2.*, cereal, directory, bytestring
+  -- hs-source-dirs:      
+  default-language:    Haskell2010
diff --git a/main.hs b/main.hs
new file mode 100644
--- /dev/null
+++ b/main.hs
@@ -0,0 +1,154 @@
+{-# LANGUAGE TemplateHaskell, PackageImports, FlexibleInstances #-}
+import Prelude hiding (foldr)
+import Text.Trifecta
+import System.IO
+import Control.Monad.State
+import Control.Lens
+import Data.Foldable
+import Control.Applicative
+import qualified Data.Map as Map
+import qualified Control.Exception as E
+import Data.Void
+import System.IO.Unsafe
+import System.IO.Error
+import Data.Monoid
+import qualified Data.ByteString.Lazy as BS
+import System.Directory
+import qualified Data.Serialize as S
+
+import "combinator-interactive" Data.Combinator
+
+data Command = Eval (Expr String)
+    | Run (Expr String)
+    | Define String (Expr String)
+    | Load FilePath String
+    | Save FilePath (Expr String)
+    | Del String
+    | Quit
+
+parseCommand :: Parser Command
+parseCommand = try define <|> run <|> load <|> del <|> quit <|> eval where
+    run = do
+        string ":run"
+        Run <$> ccParser
+    eval = do
+        Eval <$> ccParser
+    define = do
+        var <- variable
+        symbol "="
+        Define var <$> ccParser
+    load = do
+        string ":load"
+        path <- stringLiteral
+        name <- option "main" $ variable
+        return $ Load path name
+    save = do
+        string ":load"
+        path <- stringLiteral
+        expr <- ccParser
+        return $ Save path expr
+    del = do
+        string ":del"
+        Del <$> variable
+    quit = Quit <$ string ":quit"
+    
+consE x xs = S :$ (S :$ I :$ (K :$ x)) :$ (K :$ xs)
+
+runLazy :: Expr Void -> IO ()
+runLazy expr = input >>= output . vacuous . eval . (expr :$)
+
+end = consE (churchNumeral # 256) end
+
+input :: IO (Expr Void)
+input = unsafeInterleaveIO $ E.catch g $ \e -> if isEOFError e then return end else fail (show e) where
+    g = do
+        ch <- getChar
+        consE (_Combinator # churchNumeral # enum # ch) <$> input
+
+output :: Expr () -> IO ()
+output e = case e `apply` Var () of
+    Var () :$ x :$ xs -> case x ^? churchNumeral of
+        Just n
+            | n >= 256 -> return ()
+            | otherwise -> putChar (n ^. enum) >> output xs
+        Nothing -> fail "The result is not a number"
+    _ -> fail "The result is not a list"
+
+data Env = Env
+    { _definitions :: Map.Map String (Expr String)
+    }
+makeLenses ''Env
+
+applyDefs :: Map.Map String (Expr String) -> Expr String -> Expr String
+applyDefs = foldr (.) id . map (uncurry subst) . Map.toList
+
+prompt :: StateT Env IO ()
+prompt = do
+    lift $ putStr "lazy> "
+    lift $ hFlush stdout
+    cmd <- lift getLine
+    case parseString parseCommand mempty cmd of
+        Success a -> case a of
+            Eval expr -> do
+                m <- use definitions
+                lift $ putStrLn $ ccExpression # eval (applyDefs m expr)
+                prompt
+            Run expr -> do
+                m <- use definitions
+                lift $ runLazy (fmap (\x -> error $ "Unexpected free variable: " ++ x) (applyDefs m expr))
+                    `E.catch` \(E.ErrorCall msg) -> hPutStrLn stderr msg
+                    `E.catch` \e -> hPutStrLn stderr (show (e :: E.IOException))
+                prompt
+            Define name expr
+                | name `Data.Foldable.elem` expr -> do
+                    lift $ hPutStrLn stderr "Recursive definitions are not allowed"
+                    prompt
+                | otherwise -> do
+                    m <- use definitions
+                    definitions . at name ?= applyDefs m expr
+                    dump
+                    prompt
+            Load path name -> do
+                r <- parseFromFile ccParser path
+                case r of
+                    Just expr -> do
+                        definitions . at name ?= expr
+                        dump
+                        lift $ putStrLn $ "Loaded: " ++ name ++ "."
+                        prompt
+                    Nothing -> prompt
+            Save path expr -> do
+                m <- use definitions
+                lift $ writeFile path $ ccExpression # eval (applyDefs m expr)
+                prompt
+            Del name -> do
+                definitions . at name .= Nothing
+                prompt
+            Quit -> return ()
+        Failure doc -> do
+            lift $ hPutStrLn stderr $ show doc
+            prompt
+
+dump = do
+    path <- lift $ (++"/.lazyi-env") <$> getHomeDirectory
+    env <- get
+    lift $ BS.writeFile path $ S.encodeLazy env
+
+defaultEnv = Env Map.empty
+
+instance S.Serialize (Expr String) where
+    put expr = S.put (ccExpression # expr)
+    get = S.get >>= maybe (fail "parse error") return . preview ccExpression
+
+instance S.Serialize Env where
+    put (Env m) = S.put m
+    get = Env <$> S.get
+
+main = do
+    path <- (++"/.lazyi-env") <$> getHomeDirectory
+    b <- doesFileExist path
+    let w = hPutStrLn stderr "Warning: .lazyi-env is broken." >> return defaultEnv
+    env <- if b
+        then S.decodeLazy <$> BS.readFile path >>= either (const w) return
+        else return defaultEnv
+    evalStateT prompt env
