diff --git a/Data/DList.hs b/Data/DList.hs
new file mode 100644
--- /dev/null
+++ b/Data/DList.hs
@@ -0,0 +1,135 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.DList
+-- Copyright   :  (c) Don Stewart 2006
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  dons@cse.unsw.edu.au
+-- Stability   :  experimental
+-- Portability :  portable (Haskell 98)
+--
+-- Difference lists: a data structure for O(1) append on lists.
+--
+-----------------------------------------------------------------------------
+
+module Data.DList (
+
+  DList         -- abstract, instance Monoid, Functor, Monad, MonadPlus
+
+  -- * Construction
+  ,fromList      -- :: [a] -> DList a
+  ,toList        -- :: DList a -> [a]
+
+  -- * Basic functions
+  ,empty         -- :: DList a
+  ,singleton     -- :: a -> DList a
+  ,cons          -- :: a -> DList a -> DList a
+  ,snoc          -- :: DList a -> a -> DList a
+  ,append        -- :: DList a -> DList a -> DList a
+  ,concat        -- :: [DList a] -> DList a
+  ,list          -- :: b -> (a -> DList a -> b) -> DList a -> b
+  ,head          -- :: DList a -> a
+  ,tail          -- :: DList a -> DList a
+  ,unfoldr       -- :: (b -> Maybe (a, b)) -> b -> DList a
+  ,foldr         -- :: (a -> b -> b) -> b -> DList a -> b
+  ,map           -- :: (a -> b) -> DList a -> DList b
+
+  ) where
+
+import Prelude hiding (concat, foldr, map, head, tail)
+import Control.Monad
+import qualified Data.List as List (concat, foldr, map, unfoldr)
+import Data.Monoid
+
+-- | A difference list is a function that given a list, returns the
+-- original contents of the difference list prepended at the given list
+--
+-- This structure supports /O(1)/ append and snoc operations on lists.
+--
+newtype DList a = DL { unDL :: [a] -> [a] }
+
+-- | Converting a normal list to a dlist
+fromList    :: [a] -> DList a
+fromList    = DL . (++)
+
+-- | Converting a dlist back to a normal list
+toList      :: DList a -> [a]
+toList      = ($[]) . unDL
+
+-- | Create a difference list containing no elements
+empty       :: DList a
+empty       = DL id
+
+-- | Create difference list with given single element
+singleton   :: a -> DList a
+singleton   = DL . (:)
+
+-- | /O(1)/, Prepend a single element to a difference list
+cons        :: a -> DList a -> DList a
+cons x xs   = DL ((x:) . unDL xs)
+
+-- | /O(1)/, Append a single element at a difference list
+snoc        :: DList a -> a -> DList a
+snoc xs x   = DL (unDL xs . (x:))
+
+-- | Appending difference lists
+append       :: DList a -> DList a -> DList a
+append xs ys = DL (unDL xs . unDL ys)
+
+-- | Concatenate difference lists
+concat       :: [DList a] -> DList a
+concat       = List.foldr append empty
+
+-- | /O(length dl)/, List elimination, head, tail
+list :: b -> (a -> DList a -> b) -> DList a -> b
+list null cons dl =
+  case toList dl of
+    [] -> null
+    (x : xs) -> cons x (fromList xs)
+
+-- | Return the head of the list
+head :: DList a -> a
+head = list (error "Data.DList.head: empty list") (curry fst)
+
+-- | Return the tail of the list
+tail :: DList a -> DList a
+tail = list (error "Data.DList.tail: empty list") (curry snd) 
+
+-- | Unfoldr for difference lists
+unfoldr :: (b -> Maybe (a, b)) -> b -> DList a
+unfoldr pf b =
+  case pf b of
+    Nothing     -> empty
+    Just (a, b) -> cons a (unfoldr pf b)
+
+-- | Foldr over difference lists
+foldr        :: (a -> b -> b) -> b -> DList a -> b
+foldr f b    = List.foldr f b . toList
+
+-- | Map over difference lists
+map          :: (a -> b) -> DList a -> DList b
+map f        = foldr (cons . f) empty
+
+
+instance Monoid (DList a) where
+    mempty  = empty
+    mappend = append
+
+instance Functor DList where
+    fmap = map
+
+instance Monad DList where
+  m >>= k
+    -- = concat (toList (fmap k m))
+    -- = (concat . toList . fromList . List.map k . toList) m
+    -- = concat . List.map k . toList $ m
+    -- = List.foldr append empty . List.map k . toList $ m
+    -- = List.foldr (append . k) empty . toList $ m
+    = foldr (append . k) empty m
+
+  return x = singleton x
+  fail s   = empty
+
+instance MonadPlus DList where
+  mzero    = empty
+  mplus    = append
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,31 @@
+Copyright Don Stewart 2006.
+
+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 Don Stewart 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/README b/README
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,14 @@
+DLists: a Haskell list type supporting O(1) append and snoc
+
+Build instructions:
+
+    $ runhaskell Setup.lhs configure --prefix=$HOME
+    $ runhaskell Setup.lhs build
+    $ runhaskell Setup.lhs install
+
+Running the testsuite:
+    $ cd tests && runhaskell Properties.hs
+
+Author:
+    Don Stewart
+    http://www.cse.unsw.edu.au/~dons
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/dlist.cabal b/dlist.cabal
new file mode 100644
--- /dev/null
+++ b/dlist.cabal
@@ -0,0 +1,12 @@
+Name:                dlist
+Version:             0.2
+Description:         Differences lists: lists supporting efficient append
+Category:            Data
+Synopsis:            Differences lists: lists supporting efficient append
+License:             BSD3
+License-file:        LICENSE
+Author:              Don Stewart 
+Maintainer:          <dons@cse.unsw.edu.au>
+Build-Depends:       base
+ghc-options:         -O
+Exposed-modules:     Data.DList
diff --git a/tests/Parallel.hs b/tests/Parallel.hs
new file mode 100644
--- /dev/null
+++ b/tests/Parallel.hs
@@ -0,0 +1,148 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Test.QuickCheck.Parallel
+-- Copyright   :  (c) Don Stewart 2006
+-- License     :  BSD-style (see the file LICENSE)
+-- 
+-- Maintainer  :  dons@cse.unsw.edu.au
+-- Stability   :  experimental
+-- Portability :  non-portable (uses Control.Exception, Control.Concurrent)
+--
+-- A parallel batch driver for running QuickCheck on threaded or SMP systems.
+-- See the /Example.hs/ file for a complete overview.
+--
+
+module Parallel (
+    module Test.QuickCheck,
+    pRun,
+    pDet,
+    pNon
+  ) where
+
+import Test.QuickCheck
+import Data.List
+import Control.Concurrent
+import Control.Exception  hiding (evaluate)
+import System.Random
+import System.IO          (hFlush,stdout)
+import Text.Printf
+
+type Name   = String
+type Depth  = Int
+type Test   = (Name, Depth -> IO String)
+
+-- | Run a list of QuickCheck properties in parallel chunks, using
+-- 'n' Haskell threads (first argument), and test to a depth of 'd'
+-- (second argument). Compile your application with '-threaded' and run
+-- with the SMP runtime's '-N4' (or however many OS threads you want to
+-- donate), for best results.
+--
+-- > import Test.QuickCheck.Parallel
+-- >
+-- > do n <- getArgs >>= readIO . head
+-- >    pRun n 1000 [ ("sort1", pDet prop_sort1) ]
+--
+-- Will run 'n' threads over the property list, to depth 1000.
+--
+pRun :: Int -> Int -> [Test] -> IO ()
+pRun n depth tests = do
+    chan <- newChan
+    ps   <- getChanContents chan
+    work <- newMVar tests
+
+    forM_ [1..n] $ forkIO . thread work chan
+
+    let wait xs i
+            | i >= n     = return () -- done
+            | otherwise = case xs of
+                    Nothing : xs -> wait xs $! i+1
+                    Just s  : xs -> putStr s >> hFlush stdout >> wait xs i
+    wait ps 0
+
+  where
+    thread :: MVar [Test] -> Chan (Maybe String) -> Int -> IO ()
+    thread work chan me = loop
+      where
+        loop = do
+            job <- modifyMVar work $ \jobs -> return $ case jobs of
+                        []     -> ([], Nothing)
+                        (j:js) -> (js, Just j)
+            case job of
+                Nothing          -> writeChan chan Nothing -- done
+                Just (name,prop) -> do
+                    v <- prop depth
+                    writeChan chan . Just $ printf "%d: %-25s: %s" me name v
+                    loop
+
+
+-- | Wrap a property, and run it on a deterministic set of data
+pDet :: Testable a => a -> Int -> IO String
+pDet a n = mycheck Det defaultConfig
+    { configMaxTest = n
+    , configEvery   = \n args -> unlines args } a
+
+-- | Wrap a property, and run it on a non-deterministic set of data
+pNon :: Testable a => a -> Int -> IO String
+pNon a n = mycheck NonDet defaultConfig
+    { configMaxTest = n
+    , configEvery   = \n args -> unlines args } a
+
+data Mode = Det | NonDet
+
+------------------------------------------------------------------------
+
+mycheck :: Testable a => Mode -> Config -> a -> IO String
+mycheck Det config a = do
+     let rnd = mkStdGen 99  -- deterministic
+     mytests config (evaluate a) rnd 0 0 []
+
+mycheck NonDet config a = do
+    rnd <- newStdGen        -- different each run
+    mytests config (evaluate a) rnd 0 0 []
+
+mytests :: Config -> Gen Result -> StdGen -> Int -> Int -> [[String]] -> IO String
+mytests config gen rnd0 ntest nfail stamps
+  | ntest == configMaxTest config = do done "OK," ntest stamps
+  | nfail == configMaxFail config = do done "Arguments exhausted after" ntest stamps
+  | otherwise = do
+         case ok result of
+           Nothing    ->
+             mytests config gen rnd1 ntest (nfail+1) stamps
+           Just True  ->
+             mytests config gen rnd1 (ntest+1) nfail (stamp result:stamps)
+           Just False ->
+             return ( "Falsifiable after "
+                   ++ show ntest
+                   ++ " tests:\n"
+                   ++ unlines (arguments result)
+                    )
+     where
+      result      = generate (configSize config ntest) rnd2 gen
+      (rnd1,rnd2) = split rnd0
+
+done :: String -> Int -> [[String]] -> IO String
+done mesg ntest stamps =
+    return ( mesg ++ " " ++ show ntest ++ " tests" ++ table )
+  where
+    table = display
+        . map entry
+        . reverse
+        . sort
+        . map pairLength
+        . group
+        . sort
+        . filter (not . null)
+        $ stamps
+
+    display []  = ".\n"
+    display [x] = " (" ++ x ++ ").\n"
+    display xs  = ".\n" ++ unlines (map (++ ".") xs)
+
+    pairLength xss@(xs:_) = (length xss, xs)
+    entry (n, xs)         = percentage n ntest
+                          ++ " "
+                          ++ concat (intersperse ", " xs)
+
+    percentage n m        = show ((100 * n) `div` m) ++ "%"
+
+forM_ = flip mapM_
diff --git a/tests/Properties.hs b/tests/Properties.hs
new file mode 100644
--- /dev/null
+++ b/tests/Properties.hs
@@ -0,0 +1,42 @@
+
+import qualified Prelude as P
+import Prelude          hiding (concat,map,head,tail)
+import Data.List        hiding (concat,map,head,tail)
+
+import Parallel
+import Data.DList
+
+type T = [Int]
+
+prop_model x = (toList . fromList $ (x :: T)) == id x
+
+prop_empty = ([] :: T) == (toList empty :: T)
+
+prop_singleton c = ([c] :: T) == toList (singleton c)
+
+prop_cons c xs = (c : xs :: T) == toList (cons c (fromList xs))
+
+prop_snoc xs c = (xs ++ [c] :: T) == toList (snoc (fromList xs) c)
+
+prop_append xs ys = (xs ++ ys :: T) == toList (append (fromList xs) (fromList ys))
+
+prop_concat zss  = (P.concat zss) == toList (concat (P.map fromList zss))
+    where _ = zss :: [T]
+
+prop_head xs = not (null xs) ==> (P.head xs) == head (fromList xs)
+    where _ = xs :: T
+
+prop_tail xs = not (null xs) ==> (P.tail xs) == (toList . tail . fromList) xs
+    where _ = xs :: T
+
+main = pRun 2 500 [ ("model",     pDet prop_model)
+                  , ("empty",     pDet prop_empty)
+                  , ("singleton", pDet prop_singleton)
+                  , ("cons",      pDet prop_cons)
+                  , ("snoc",      pDet prop_snoc)
+                  , ("append",    pDet prop_append)
+                  , ("concat",    pDet prop_concat)
+                  , ("head",      pDet prop_head)
+                  , ("tail",      pDet prop_tail)
+                  ]
+
