packages feed

implicit-params (empty) → 0.1

raw patch · 5 files changed

+297/−0 lines, 5 filesdep +basedep +data-defaultsetup-changed

Dependencies added: base, data-default

Files

+ CONTRIBUTORS view
@@ -0,0 +1,1 @@+Shane O'Brien <shane@duairc.com>
+ LICENSE view
@@ -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.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ implicit-params.cabal view
@@ -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
+ src/Data/Implicit.hs view
@@ -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