newtype-deriving (empty) → 0.1.0
raw patch · 8 files changed
+393/−0 lines, 8 filesdep +basedep +base-preludedep +eithersetup-changed
Dependencies added: base, base-prelude, either, monad-control, newtype-deriving, template-haskell, transformers, transformers-base
Files
- LICENSE +22/−0
- Setup.hs +2/−0
- demo/Main.hs +31/−0
- library/NewtypeDeriving.hs +94/−0
- library/NewtypeDeriving/Reification.hs +41/−0
- library/NewtypeDeriving/Rendering.hs +96/−0
- library/NewtypeDeriving/TH.hs +11/−0
- newtype-deriving.cabal +96/−0
+ LICENSE view
@@ -0,0 +1,22 @@+Copyright (c) 2014, Nikita Volkov++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.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ demo/Main.hs view
@@ -0,0 +1,31 @@+{-# LANGUAGE UndecidableInstances, TypeFamilies, FlexibleInstances,+ TemplateHaskell, GeneralizedNewtypeDeriving,+ MultiParamTypeClasses #-}+module Main where++import Prelude ()+import BasePrelude+import NewtypeDeriving+import Control.Monad.Base+import Control.Monad.Trans.Control+import Control.Monad.Trans.Class+import Control.Monad.Trans.Either+import Control.Monad.Trans.Maybe+import Control.Monad.Trans.State+import Control.Monad.Trans.Reader+import Control.Monad.Trans.Writer+++main =+ return ()+++newtype T m a =+ T (ReaderT Int (StateT Char (WriterT [Int] (EitherT String (MaybeT m)))) a)+ deriving (Functor, Applicative, Monad)++monadTransInstance ''T+monadTransControlInstance ''T+monadBaseTransformerInstance ''T+monadBaseControlTransformerInstance ''T+
+ library/NewtypeDeriving.hs view
@@ -0,0 +1,94 @@+-- |+-- This module provides+-- Template Haskell based derivers for typical newtype instances, +-- which the @GeneralizedNewtypeDeriving@ extension refuses to handle. +-- +-- Here is what it allows you to do:+-- +-- >{-# LANGUAGE UndecidableInstances, TypeFamilies, FlexibleInstances,+-- > TemplateHaskell, GeneralizedNewtypeDeriving,+-- > MultiParamTypeClasses #-}+-- >+-- >import NewtypeDeriving+-- >import Control.Monad.Base+-- >import Control.Monad.Trans.Control+-- >import Control.Monad.Trans.Class+-- >import Control.Monad.Trans.Either+-- >import Control.Monad.Trans.Maybe+-- >import Control.Monad.Trans.State+-- >import Control.Monad.Trans.Reader+-- >import Control.Monad.Trans.Writer+-- >+-- >newtype T m a =+-- > T (ReaderT Int (StateT Char (WriterT [Int] (EitherT String (MaybeT m)))) a)+-- > deriving (Functor, Applicative, Monad)+-- >+-- >monadTransInstance ''T+-- >monadTransControlInstance ''T+-- >monadBaseTransformerInstance ''T+-- >monadBaseControlTransformerInstance ''T+module NewtypeDeriving where++import BasePrelude+import Language.Haskell.TH+import qualified NewtypeDeriving.Reification as Reification+import qualified NewtypeDeriving.Rendering as Rendering+++-- |+-- Given a name of a newtype wrapper +-- produce an instance of+-- @Control.Monad.Trans.Class.'Control.Monad.Trans.Class.MonadTrans'@.+monadTransInstance :: Name -> Q [Dec]+monadTransInstance n =+ do+ Reification.Newtype typeName conName innerType <-+ join $ fmap (either fail return) $+ Reification.reifyNewtype n+ let+ layers =+ unfoldr Reification.peelTransformer $ + case innerType of AppT m _ -> m+ return $ pure $+ Rendering.monadTransInstance (ConT typeName) conName (length layers)++-- |+-- Given a name of a newtype wrapper +-- produce an instance of+-- @Control.Monad.Base.'Control.Monad.Base.MonadBase'@,+-- which is specialised for monad transformers.+monadBaseTransformerInstance :: Name -> Q [Dec]+monadBaseTransformerInstance n =+ do+ Reification.Newtype typeName conName innerType <-+ join $ fmap (either fail return) $+ Reification.reifyNewtype n+ return $ pure $+ Rendering.monadBaseTransformerInstance (ConT typeName) conName++-- |+-- Given a name of a newtype wrapper +-- produce an instance of+-- @Control.Monad.Trans.Control.'Control.Monad.Trans.Control.MonadTransControl'@.+monadTransControlInstance :: Name -> Q [Dec]+monadTransControlInstance n =+ do+ Reification.Newtype typeName conName innerType <-+ join $ fmap (either fail return) $+ Reification.reifyNewtype n+ let+ layers =+ unfoldr Reification.peelTransformer $ + case innerType of AppT m _ -> m+ return $ pure $ + Rendering.monadTransControlInstance (ConT typeName) conName layers++-- |+-- Given a name of a newtype wrapper +-- produce an instance of+-- @Control.Monad.Trans.Control.'Control.Monad.Trans.Control.MonadBaseControl'@,+-- which is specialised for monad transformers.+monadBaseControlTransformerInstance :: Name -> Q [Dec]+monadBaseControlTransformerInstance n =+ return $ pure $+ Rendering.monadBaseControlTransformerInstance (ConT n)
+ library/NewtypeDeriving/Reification.hs view
@@ -0,0 +1,41 @@+module NewtypeDeriving.Reification where++import BasePrelude+import Language.Haskell.TH++++data Newtype =+ Newtype {+ newtypeTypeName :: Name,+ newtypeConstructorName :: Name,+ newtypeInnerType :: Type+ }+ deriving (Show)++reifyNewtype :: Name -> Q (Either String Newtype)+reifyNewtype =+ fmap parseInfo . reify+ where+ parseInfo =+ \case+ TyConI (NewtypeD _ typeName _ con derivations) -> do+ (conName, innerType) <-+ case con of+ NormalC n [(_, t)] -> Right (n, t)+ RecC n [(_, _, t)] -> Right (n, t)+ _ -> Left $ "Invalid constructor: " <> show con+ return $ Newtype typeName conName innerType+ i ->+ Left $ "Invalid type of a name"++-- |+-- Given a kind @* -> *@ type, +-- peel off a kind @(* -> *) -> (* -> *)@ type (the monad-transformer)+-- and another @* -> *@ type (the inner monad).+peelTransformer :: Type -> Maybe (Type, Type)+peelTransformer =+ \case+ AppT t m -> Just (t, m)+ _ -> Nothing+
+ library/NewtypeDeriving/Rendering.hs view
@@ -0,0 +1,96 @@+module NewtypeDeriving.Rendering where++import BasePrelude+import Control.Monad.Base+import Control.Monad.Trans.Control+import Control.Monad.Trans.Class+import NewtypeDeriving.TH+import Language.Haskell.TH+++monadTransInstance + :: Type -- ^ Type of Newtype+ -> Name -- ^ Constructor name+ -> Int -- ^ Amount of inner layers+ -> Dec+monadTransInstance transformerType conName layersCount =+ head $ purifyQ $+ [d|+ instance MonadTrans $(pure transformerType) where+ lift =+ $(pure liftExp)+ |]+ where+ liftExp =+ foldl' composeExp (ConE conName) $ replicate layersCount (VarE 'lift)++monadBaseTransformerInstance+ :: Type+ -> Name+ -> Dec+monadBaseTransformerInstance transformerType conName =+ head $ purifyQ $+ [d|+ instance MonadBase b m => MonadBase b ($(pure transformerType) m) where+ liftBase =+ $(conE conName) . liftBase+ |]++monadTransControlInstance + :: Type -- ^ Type of Newtype+ -> Name -- ^ Constructor name+ -> [Type] -- ^ Layers of inner transfomer types+ -> Dec+monadTransControlInstance transformerType conName layers =+ head $ purifyQ $+ [d|+ instance MonadTransControl $(pure transformerType) where+ type StT $(pure transformerType) $(varT stArgName) = + $(pure stType)+ liftWith =+ $(pure liftWithExp)+ restoreT =+ $(pure restoreTExp)+ |]+ where+ restoreTExp =+ foldl' composeExp (ConE conName) $ + replicate (length layers) (VarE 'restoreT)+ liftWithExp =+ LamE [VarP onUnliftVarName] $+ AppE (ConE conName) $+ foldr' (\n -> AppE (VarE 'liftWith) . LamE [VarP n])+ (AppE (VarE onUnliftVarName) unliftExp)+ (unliftNames)+ where+ onUnliftVarName =+ mkName "onUnlift"+ unliftNames =+ zipWith (\_ i -> mkName $ "unlift" <> show i) layers [1..]+ unliftExp =+ foldr' composeExp unwrapExp $ map VarE $ reverse unliftNames+ unwrapExp =+ LamE [ConP conName [VarP mVarName]] (VarE mVarName)+ where+ mVarName = + mkName "m"+ stArgName =+ mkName "a"+ stType =+ foldl' (flip AppT) (VarT stArgName) $ map (AppT (ConT ''StT)) layers++monadBaseControlTransformerInstance+ :: Type+ -> Dec+monadBaseControlTransformerInstance t =+ head $ purifyQ $+ [d|+ instance MonadBaseControl b m => MonadBaseControl b ($(pure t) m) where+ type StM ($(pure t) m) a = ComposeSt $(pure t) m a+ liftBaseWith = defaultLiftBaseWith+ restoreM = defaultRestoreM+ |]++composeExp :: Exp -> Exp -> Exp+composeExp a b =+ UInfixE a (VarE '(.)) b
+ library/NewtypeDeriving/TH.hs view
@@ -0,0 +1,11 @@+module NewtypeDeriving.TH where++import BasePrelude+import Language.Haskell.TH+++purifyQ :: Q a -> a+purifyQ = unsafePerformIO . runQ++tryToReify :: Name -> Q (Maybe Info)+tryToReify n = recover (return Nothing) (fmap Just $ reify n)
+ newtype-deriving.cabal view
@@ -0,0 +1,96 @@+name:+ newtype-deriving+version:+ 0.1.0+synopsis:+ Instance derivers for newtype wrappers+description:+ Template Haskell based derivers for typical newtype instances, + which the @GeneralizedNewtypeDeriving@ extension refuses to handle.+ .+ Amongst others provides support for the \"monad-control\" classes:+ .+ * @Control.Monad.Trans.Control.'Control.Monad.Trans.Control.MonadTransControl'@+ .+ * @Control.Monad.Trans.Control.'Control.Monad.Trans.Control.MonadBaseControl'@+category:+ Control, Template Haskell+homepage:+ https://github.com/nikita-volkov/newtype-deriving +bug-reports:+ https://github.com/nikita-volkov/newtype-deriving/issues +author:+ Nikita Volkov <nikita.y.volkov@mail.ru>+maintainer:+ Nikita Volkov <nikita.y.volkov@mail.ru>+copyright:+ (c) 2014, Nikita Volkov+license:+ MIT+license-file:+ LICENSE+build-type:+ Simple+cabal-version:+ >=1.10+++source-repository head+ type:+ git+ location:+ git://github.com/nikita-volkov/newtype-deriving.git+++library+ hs-source-dirs:+ library+ ghc-options:+ -funbox-strict-fields+ default-extensions:+ Arrows, BangPatterns, ConstraintKinds, DataKinds, DefaultSignatures, DeriveDataTypeable, DeriveFunctor, DeriveGeneric, EmptyDataDecls, FlexibleContexts, FlexibleInstances, FunctionalDependencies, GADTs, GeneralizedNewtypeDeriving, ImpredicativeTypes, LambdaCase, LiberalTypeSynonyms, MagicHash, MultiParamTypeClasses, MultiWayIf, NoImplicitPrelude, NoMonomorphismRestriction, OverloadedStrings, PatternGuards, ParallelListComp, QuasiQuotes, RankNTypes, RecordWildCards, ScopedTypeVariables, StandaloneDeriving, TemplateHaskell, TupleSections, TypeFamilies, TypeOperators, UnboxedTuples+ default-language:+ Haskell2010+ other-modules:+ NewtypeDeriving.Reification+ NewtypeDeriving.Rendering+ NewtypeDeriving.TH+ exposed-modules:+ NewtypeDeriving+ build-depends:+ template-haskell >= 2.7 && < 2.10,+ monad-control >= 1.0 && < 1.1,+ transformers-base == 0.4.*,+ transformers >= 0.3 && < 0.5,+ base-prelude >= 0.1.3 && < 0.2,+ base >= 4.5 && < 4.8+++-- Well, it's not a benchmark actually, +-- but in Cabal there's no better way to specify an executable, +-- which is not intended for distribution.+benchmark demo+ type: + exitcode-stdio-1.0+ hs-source-dirs:+ demo+ main-is:+ Main.hs+ ghc-options:+ -O2+ -threaded+ "-with-rtsopts=-N"+ -funbox-strict-fields+ -ddump-splices+ default-language:+ Haskell2010+ build-depends:+ newtype-deriving,+ either >= 4.3 && < 4.4,+ monad-control >= 1.0 && < 1.1,+ transformers-base == 0.4.*,+ transformers >= 0.3 && < 0.5,+ base-prelude >= 0.1.3 && < 0.2,+ base >= 4.5 && < 4.8++