diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,11 @@
+Copyright 2020 coord_e, Satoshi Egi
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. 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.
+
+3. Neither the name of the copyright holder nor the names of its 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 HOLDER 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/backtracking.cabal b/backtracking.cabal
new file mode 100644
--- /dev/null
+++ b/backtracking.cabal
@@ -0,0 +1,70 @@
+cabal-version:       >=1.10
+-- Initial package description 'backtracking.cabal' generated by 'cabal
+-- init'.  For further documentation, see
+-- http://haskell.org/cabal/users-guide/
+
+name:                backtracking
+version:             0.1.0
+synopsis:            A backtracking monad
+description:         This library provides a backtracking monad following Spivey's paper "Algebras for combinatorial search".
+-- bug-reports:
+license:             BSD3
+license-file:        LICENSE
+author:              coord_e, Satoshi Egi
+maintainer:          Satoshi Egi <egi@egison.org>
+-- copyright:
+category:            Control
+build-type:          Simple
+extra-source-files:  CHANGELOG.md
+
+library
+  hs-source-dirs:     src
+  exposed-modules:
+      Control.Monad.Search
+  build-depends:
+  build-depends:
+      base                        >=4.8   && <5
+    , transformers
+  default-language:    Haskell2010
+  default-extensions:
+    DataKinds
+    DefaultSignatures
+    DerivingStrategies
+    ExplicitForAll
+    FlexibleContexts
+    FlexibleInstances
+    GeneralizedNewtypeDeriving
+    LambdaCase
+    MultiParamTypeClasses
+    NamedFieldPuns
+    PolyKinds
+    RankNTypes
+    ScopedTypeVariables
+    StandaloneDeriving
+    TupleSections
+    TypeFamilies
+    TypeOperators
+  ghc-options:
+    -Wall -Wno-type-defaults
+
+test-suite test
+  type:               exitcode-stdio-1.0
+  hs-source-dirs:     test
+  main-is:            test.hs
+  ghc-options:
+    -Wall -threaded -rtsopts -with-rtsopts=-N -Wno-type-defaults
+  default-language:   Haskell2010
+  build-depends:
+      base
+    , primes
+    , backtracking
+    , tasty
+    , tasty-hunit
+  default-extensions:
+    GADTs
+    QuasiQuotes
+    TemplateHaskell
+    TypeApplications
+  -- cabal-fmt: expand test
+  other-modules:      Spec
+  build-tool-depends: tasty-discover:tasty-discover -any
diff --git a/src/Control/Monad/Search.hs b/src/Control/Monad/Search.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Monad/Search.hs
@@ -0,0 +1,84 @@
+-- |
+--
+-- Module:      Control.Monad.Search
+-- Description: Monad for backtracking
+-- Stability:   experimental
+
+module Control.Monad.Search
+  ( MonadSearch(..)
+  , DFS
+  , dfs
+  , BFS
+  , bfs
+  )
+where
+
+import           Control.Applicative            ( Alternative(..) )
+import           Control.Monad                  ( ap, MonadPlus(..) )
+
+-- | 'MonadSearch' represents searches with backtracking.
+class MonadPlus m => MonadSearch m where
+  fromList :: [a] -> m a
+  toList   :: m a -> [a]
+
+  failure  :: m a -> Bool
+  default failure :: m a -> Bool
+  failure m = null (toList m)
+  lnot     :: DFS a -> m ()
+  default lnot :: DFS a -> m ()
+  lnot m = if failure m then fromList [()] else mzero
+  guard    :: Bool -> m ()
+  default guard :: Bool -> m ()
+  guard t = if t then fromList [()] else mzero
+
+-- | DFS implementation of 'MonadSearch'.
+newtype DFS a = DFS { unDFS :: [a] }
+  deriving newtype (Functor, Applicative, Monad, Alternative, MonadPlus)
+
+instance MonadSearch DFS where
+  {-# INLINE fromList #-}
+  fromList xs = DFS xs
+  {-# INLINE toList #-}
+  toList (DFS xs) = xs
+
+dfs :: a -> DFS a
+dfs x = DFS [x]
+
+-- | BFS implementation of 'MonadSearch'.
+newtype BFS a = BFS { unBFS :: [[a]] }
+
+instance Functor BFS where
+  fmap f (BFS xss) = BFS $ map (\xs -> map f xs) xss
+
+instance Applicative BFS where
+  pure = return
+  (<*>) = ap
+
+instance Monad BFS where
+  return x = BFS [[x]]
+  BFS [] >>= _ = BFS []
+  BFS (xs:xss) >>= f = foldl mplus mzero (map f xs) `mplus` shift (BFS xss >>= f)
+   where
+    shift :: BFS a -> BFS a
+    shift (BFS xss) = BFS ([] : xss)
+
+instance Alternative BFS where
+  empty = mzero
+  (<|>) = mplus
+
+instance MonadPlus BFS where
+  mzero = BFS []
+  mplus (BFS xss) (BFS yss) = BFS (merge xss yss)
+   where
+    merge :: [[a]] -> [[a]] -> [[a]]
+    merge [] [] = []
+    merge xss [] = xss
+    merge [] yss = yss
+    merge (xs:xss) (ys:yss) = (xs ++ ys) : merge xss yss
+
+instance MonadSearch BFS where
+  fromList xs = BFS (map (\x -> [x]) xs)
+  toList (BFS xss) = concat xss
+
+bfs :: a -> BFS a
+bfs x = BFS [[x]]
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,58 @@
+module Spec
+  (
+    test_dfs
+  , test_bfs
+  )
+where
+
+import           Control.Monad.Search
+
+import           Test.Tasty
+import           Test.Tasty.HUnit
+
+
+splits :: [a] -> [([a], [a])]
+splits [] = [([], [])]
+splits (x:xs) = ([], x:xs) : map (\(as, ys) -> (x:as, ys)) (splits xs)
+
+
+get :: [a] -> [(a, [a])]
+get xs = map (\x -> (x, xs)) xs
+
+
+test_dfs :: [TestTree]
+test_dfs =
+  [
+   testCase "splits"
+    $ assertEqual "simple" [([], [1, 2]), ([1], [2]), ([1, 2], [])]
+    $ toList $ dfs [1, 2] >>= fromList . splits >>= \(hs, ts) -> pure (hs, ts)
+ , testCase "double cons"
+    $ assertEqual "simple" [(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3)]
+    $ toList $ dfs [1, 2, 3] >>= fromList . get >>= \(x, xs) -> (fromList . get) xs >>= \(y, _) -> pure (x, y)
+   ]
+
+test_bfs :: [TestTree]
+test_bfs =
+  [
+   testCase "double cons"
+    $ assertEqual "simple" [(1,1),(1,2),(2,1),(1,3),(2,2),(3,1),(2,3),(3,2),(3,3)]
+    $ toList $ bfs [1, 2, 3] >>= fromList . get >>= \(x, xs) -> (fromList . get) xs >>= \(y, _) -> pure (x, y)
+ , testCase "infinite double cons"
+    $ assertEqual "simple" [(1,1),(1,2),(2,1),(1,3),(2,2),(3,1),(1,4),(2,3),(3,2)]
+    $ take 9 $ toList $ bfs [1..] >>= fromList . get >>= \(x, xs) -> (fromList . get) xs >>= \(y, _) -> pure (x, y)
+ , testCase "guard"
+    $ assertEqual "simple" [(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9)]
+    $ take 9 $ toList $ bfs [1..] >>= fromList . get >>= \(x, xs) -> (fromList . get) xs >>= \(y, _) -> guard (x == y) >> pure (x, y)
+ , testCase "not pattern"
+    $ assertEqual "simple" [(1,2),(2,1),(1,3),(3,1),(1,4),(2,3),(3,2),(4,1),(1,5)]
+    $ take 9 $ toList $ bfs [1..] >>= fromList . get >>= \(x, xs) -> (fromList . get) xs >>= \(y, _) -> lnot (guard (x == y) >> pure ()) >> pure (x, y)
+ , testCase "not pattern in do notation"
+    $ assertEqual "simple" [(1,2),(2,1),(1,3),(3,1),(1,4),(2,3),(3,2),(4,1),(1,5)]
+    $ take 9 $ toList $ do
+       (x, xs) <- bfs [1..] >>= fromList . get
+       (y, _) <- (fromList . get) xs
+       return ()
+       lnot (guard (x == y) >> pure ())
+       pure (x, y)
+   ]
+
diff --git a/test/test.hs b/test/test.hs
new file mode 100644
--- /dev/null
+++ b/test/test.hs
@@ -0,0 +1,1 @@
+{-# OPTIONS_GHC -F -pgmF tasty-discover #-}
