diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2014 AlephCloud, Inc.
+
+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/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/data-carousel.cabal b/data-carousel.cabal
new file mode 100644
--- /dev/null
+++ b/data-carousel.cabal
@@ -0,0 +1,26 @@
+-- Initial data-carousel.cabal generated by cabal init.  For further
+-- documentation, see http://haskell.org/cabal/users-guide/
+
+name:                data-carousel
+version:             0.1.0.0
+synopsis:            A rotating sequence data structure
+license:             MIT
+license-file:        LICENSE
+author:              Jon Sterling
+maintainer:          jon@jonmsterling.com
+copyright:           Copyright (c) 2014 AlephCloud, Inc.
+category:            Data
+build-type:          Simple
+cabal-version:       >=1.10
+
+source-repository head
+    type: git
+    location: https://github.com/alephcloud/hs-data-carousel.git
+
+library
+  exposed-modules:     Data.Carousel
+  build-depends:       base >=4.7 && <4.8,
+                       containers >=0.5.5.1,
+                       lens >=4.5
+  hs-source-dirs:      src
+  default-language:    Haskell2010
diff --git a/src/Data/Carousel.hs b/src/Data/Carousel.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Carousel.hs
@@ -0,0 +1,106 @@
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE UnicodeSyntax #-}
+
+-- |
+-- Module: Data.Carousel
+-- Copyright: Copyright © 2014 AlephCloud Systems, Inc.
+-- License: MIT
+-- Maintainer: Jon Sterling <jsterling@alephcloud.com>
+-- Stability: experimental
+--
+module Data.Carousel
+( Carousel
+, empty
+, cursor
+, moveLeft
+, moveRight
+, dropCursor
+, nub
+, append
+, clSequence
+, clList
+) where
+
+import Control.Lens
+import qualified Data.Foldable as F
+import qualified Data.List as L
+import qualified Data.Sequence as S
+
+newtype Carousel α
+  = Carousel
+  { _clSequence ∷ S.Seq α
+  } deriving (Show, Eq)
+
+instance Functor Carousel where
+  fmap f (Carousel sq) = Carousel $ fmap f sq
+
+instance F.Foldable Carousel where
+  foldMap f (Carousel sq) = F.foldMap f sq
+
+instance Traversable Carousel where
+  traverse f (Carousel sq) = fmap Carousel (traverse f sq)
+
+clSequence ∷ Iso (Carousel α) (Carousel β) (S.Seq α) (S.Seq β)
+clSequence = iso _clSequence Carousel
+
+clList ∷ Iso (Carousel α) (Carousel β) [α] [β]
+clList = clSequence . iso F.toList S.fromList
+
+
+-- | There is guaranteed to be a cursor so long as the carousel is non-empty.
+cursor ∷ Traversal' (Carousel α) α
+cursor = clSequence . _head
+
+-- | You can delete the cursor from the carousel; the items to its right will
+-- move one over to the left.
+dropCursor
+  ∷ Carousel α
+  → Carousel α
+dropCursor = clSequence %~ (^. _tail)
+
+-- | The carousel may be rotated to the right; this operation is written so as
+-- to always guarantee the presence of a cursor in a non-empty carousel.
+moveRight
+  ∷ Carousel α
+  → Carousel α
+moveRight = clSequence %~ rotate . S.viewl
+  where
+    rotate
+      ∷ S.ViewL α
+      → S.Seq α
+    rotate S.EmptyL = S.empty
+    rotate (x S.:< xs) = xs S.|> x
+
+-- | The carousel may be rotated to the left; this operation is written so as
+-- to always guarantee the presence of a cursor in a non-empty carousel.
+moveLeft
+  ∷ Carousel α
+  → Carousel α
+moveLeft = clSequence %~ rotate . S.viewr
+  where
+    rotate
+      ∷ S.ViewR α
+      → S.Seq α
+    rotate S.EmptyR = S.empty
+    rotate (xs S.:> x) = x S.<| xs
+
+-- | The empty carousel.
+empty
+  ∷ Carousel α
+empty = Carousel S.empty
+
+-- | Append a list of elements to the right side of the carousel.
+append
+  ∷ [α]
+  → Carousel α
+  → Carousel α
+append xs = clSequence %~ (S.>< S.fromList xs)
+
+-- | Remove all duplicate elements from the carousel. (TODO: this is inefficient)
+nub
+  ∷ Eq α
+  ⇒ Carousel α
+  → Carousel α
+nub = clList %~ L.nub
