diff --git a/CONTRIBUTORS b/CONTRIBUTORS
new file mode 100644
--- /dev/null
+++ b/CONTRIBUTORS
@@ -0,0 +1,1 @@
+Shane O'Brien <shane@duairc.com>
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2013, Shane O'Brien
+
+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 Shane O'Brien 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/implicit-params.cabal b/implicit-params.cabal
new file mode 100644
--- /dev/null
+++ b/implicit-params.cabal
@@ -0,0 +1,37 @@
+name:           implicit-params
+version:        0.1
+synopsis:       Named and unnamed implicit parameters with defaults.
+license:        BSD3
+license-file:   LICENSE
+author:         Shane O'Brien
+maintainer:     shane@duairc.com
+stability:      Experimental
+category:       Data
+cabal-version:  >= 1.6
+build-type:     Simple
+homepage:       http://github.com/duairc/implicit
+bug-reports:    http://github.com/duairc/implicit/issues
+description:
+  Named and unnamed implicit parameters with defaults using type classes and
+  constraint hacks. For examples, see "Data.Implicit".
+
+extra-source-files:
+  CONTRIBUTORS,
+  LICENSE
+
+library
+  hs-source-dirs:
+    src
+
+  exposed-modules:
+    Data.Implicit
+
+  build-depends:
+    base >= 4.6 && < 5,
+    data-default > 0.2 && < 1
+
+  ghc-options: -Wall
+
+source-repository head
+  type:     git
+  location: http://github.com/duairc/implicit
diff --git a/src/Data/Implicit.hs b/src/Data/Implicit.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Implicit.hs
@@ -0,0 +1,227 @@
+{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE KindSignatures #-}
+{-# LANGUAGE ImplicitParams #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE OverlappingInstances #-}
+{-# LANGUAGE Rank2Types #-}
+{-# LANGUAGE UndecidableInstances #-}
+
+{-|
+
+"Data.Implicit" provides both named and unnamed implicit parameters that
+support default values (given by the 'Default' class from the @data-default@
+package). It makes no use of the @ImplicitParams@ extension and instead
+everything is done using type classes.
+
+Here is an example of unnamed implicit parameters:
+
+@
+{\-\# LANGUAGE FlexibleContexts #-\}
+import "Data.Implicit"
+
+putParam :: 'Implicit_' String => IO ()
+putParam = putStrLn $ \"Param was: \" ++ show ('param_' :: String)
+@
+
+We define @putParam@, which is a simple function which takes an implicit
+parameter of type @String@, and prints it to the screen. The 'param_' function
+is used to retrieve the unnamed implicit parameter of type @String@ from
+@putParam@'s context. The type signature is necessary to force 'param_' to
+return a @String@, as this cannot be inferred due to the polymorphism of
+@show@.
+
+>>> putParam
+Param was ""
+
+This is how we call @putParam@ without specifying its implicit parameters. If
+an implicit parameter is left unspecified, its value is defaulted to 'def',
+assuming that its type has a 'Default' instance. If not, then it is a type
+error not to specify the value of an implicit parameter.
+
+>>> putParam $~ "hello, world"
+Param was "hello, world"
+
+The operator '$~' takes a function @f@ and a value to which to set the
+homotypic implicit parameter on @f@. It applies the implicit parameter to @f@
+and returns the result. There is also a prefix version of @$~@ whose arguments
+are flipped called 'setParam_'.
+
+Here is an example of named implicit parameters:
+
+@
+{\-\# LANGUAGE DataKinds, FlexibleContexts, RankNTypes #-\}
+import "Data.Implicit"
+import "Data.Proxy"
+
+putFooBar :: ('Implicit' \"foo\" String, 'Implicit' \"bar\" String) => IO ()
+putFooBar = do
+    putStrLn $ \"foo was: \" ++ show foo
+    putStrLn $ \"bar was: \" ++ show bar
+
+foo :: 'Implicit' \"foo\" String => String
+foo = 'param' (Proxy :: Proxy \"foo\")
+
+bar :: 'Implicit' \"bar\" String => String
+bar = 'param' (Proxy :: Proxy \"bar\")
+
+setFoo :: String -> ('Implicit' \"foo\" String => a) -> a
+setFoo = 'setParam' (Proxy :: Proxy \"foo\")
+
+setBar :: String -> ('Implicit' \"bar\" String => a) -> a
+setBar = 'setParam' (Proxy :: Proxy \"bar\")
+@
+
+The 'Implicit' constraint is the named equivalent of 'Implicit_'. It takes an
+additional argument of kind 'Symbol' (which requires the @DataKinds@
+extension; see the "GHC.TypeLits" module) to specify the name of the implicit
+parameter. 'param' and 'setParam' work like their unnamed counterparts
+'param_' and 'setParam_', but they also take a proxy argument to specify the
+name of the implicit parameter. The code above defines the wrappers @foo@ and
+@bar@ and @setFoo@ and @setBar@ around @param@ and @setParam@ respectively,
+which hide all the (slightly ugly) proxy stuff.
+
+>>> putFooBar
+foo was: ""
+bar was: ""
+
+Once again, the defaults of unspecified implicit parameters are given by the
+'Default' class.
+
+>>> setFoo "hello, world" putFooBar
+foo was: "hello, world"
+bar was: ""
+
+>>> setBar "goodbye" $ setFoo "hello, world" putFooBar
+foo was: "hello, world"
+bar was: "goodbye"
+
+An infix version of @setParam@ is also provided, '$$~'. Using @$$~@, the above
+example would be:
+
+>>> putFooBar $$~ (Proxy :: Proxy "foo", "hello, world") $$~ (Proxy :: Proxy "bar", "goodbye")
+foo was: "hello, world"
+bar was: "goodbye
+
+-}
+
+module Data.Implicit
+    ( Implicit
+    , param
+    , setParam
+    , ($$~)
+
+    , Implicit_
+    , param_
+    , setParam_
+    , ($~)
+    )
+where
+
+import           Data.Default (Default, def)
+import           GHC.TypeLits (Symbol)
+import           GHC.Exts (Any)
+import           Unsafe.Coerce (unsafeCoerce)
+
+
+------------------------------------------------------------------------------
+-- | The constraint @'Implicit' \"foo\" String@ on a function @f@ indicates
+-- that an implicit parameter named @\"foo\"@ of type @String@ is passed to
+-- @f@.
+--
+-- The name @\"foo\"@ is a type of kind 'Symbol' (from the "GHC.TypeLits"
+-- module). The @DataKinds@ extension is required to refer to 'Symbol'-kinded
+-- types.
+class Implicit (s :: Symbol) a where
+    _param :: proxy s -> a
+
+
+------------------------------------------------------------------------------
+instance Default a => Implicit s a where
+    _param _ = def
+
+
+------------------------------------------------------------------------------
+-- | 'param' retrieves the implicit parameter named @s@ of type @a@ from the
+-- context @'Implicit' s a@. The name @s@ is specified by a proxy argument
+-- passed to @param@.
+param :: Implicit s a => proxy s -> a
+param = _param
+
+
+------------------------------------------------------------------------------
+-- | 'setParam' supplies a value for an implicit parameter named @s@ to a
+-- function which takes a homotypic and homonymous implicit parameter. The
+-- name @s@ is specified by a proxy argument passed to @setParam@.
+setParam :: proxy s -> a -> (Implicit s a => b) -> b
+setParam = using
+
+
+------------------------------------------------------------------------------
+-- | An infix version of 'setParam' with flipped arguments.
+($$~) :: (Implicit s a => b) -> (proxy s, a) -> b
+($$~) f (proxy, a) = using proxy a f
+
+
+------------------------------------------------------------------------------
+-- | The constraint @'Implicit_' String@ on a function @f@ indicates that an
+-- unnamed implicit parameter of type @String@ is passed to @f@.
+type Implicit_ = Implicit Any
+
+
+------------------------------------------------------------------------------
+-- | 'param_' retrieves the unnamed implicit parameter of type @a@ from the
+-- context @'Implicit_' a@.
+param_ :: Implicit_ a => a
+param_ = param (Proxy :: Proxy Any)
+
+
+------------------------------------------------------------------------------
+-- | 'setParam_' supplies a value for an unnamed implicit parameter to a
+-- function which takes a homotypic implicit parameter.
+setParam_ :: a -> (Implicit_ a => b) -> b
+setParam_ = setParam (Proxy :: Proxy Any)
+
+
+------------------------------------------------------------------------------
+-- | An infix version of 'setParam_' with flipped arguments.
+($~) :: (Implicit_ a => b) -> a -> b
+infixr 1 $~
+f $~ a = using (Proxy :: Proxy Any) a f
+
+
+------------------------------------------------------------------------------
+data Proxy (s :: Symbol) = Proxy
+
+
+------------------------------------------------------------------------------
+newtype Lift a = Lift a
+
+
+------------------------------------------------------------------------------
+newtype Tagged (s :: Symbol) a = Tagged a
+
+
+------------------------------------------------------------------------------
+data Dict c where
+    Dict :: c => Dict c
+
+
+------------------------------------------------------------------------------
+using :: proxy s -> a -> (Implicit s a => b) -> b
+using p a = with (unlift (dict p a))
+  where
+    with :: Dict c -> (c => b) -> b
+    with Dict b = b
+
+    unlift :: Dict (c (Lift p)) -> Dict (c p)
+    unlift = unsafeCoerce
+
+    dict :: proxy s -> a -> Dict (Implicit s (Lift a))
+    dict _ a' = let ?param = Tagged a' in Dict
+
+
+------------------------------------------------------------------------------
+instance (?param :: Tagged s a) => Implicit s (Lift a) where
+    _param _ = let Tagged a = ?param in Lift a
