{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE Rank2Types #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE UndecidableInstances #-} ---------------------------------------------------------------------------- -- | -- Module : Type.Class.Nullary -- Copyright : 2015 Derek Elkins -- License : BSD2 -- -- Maintainer : Derek Elkins -- Stability : experimental -- Portability : non-portable -- -- Provides a framework for defining and using nullary type classes -- without needing orphan instances. To do this requires some evil -- to locally generate a type class instances. This library -- encapsulates that evil and provides a mechanism for safely -- defining new nullary type classes. -- -- To define a nullary type class, you use the following pattern: -- -- > -- The following four extensions are necessary. -- > {-# LANGUAGE FlexibleContexts #-} -- > {-# LANGUAGE MultiParamTypeClasses #-} -- > {-# LANGUAGE Rank2Types #-} -- > {-# LANGUAGE UndecidableInstances #-} -- > -- > -- Not exported unless you want to allow users to opt out of -- > -- the checking by making an instance for Tag PartialTag. -- > data PartialTag -- > -- > -- The nullary type class. It can have members, but it's not -- > -- clear this accomplishes anything. -- > class Partial -- > -- > -- Enable this library. Instances like this unfortunately -- > -- require UndecidableInstances. -- > instance Tag PartialTag => Partial -- > -- > -- Wrap unsafeTag for user convenience. -- > partial :: (Partial => a) -> a -- > partial = unsafeTag (Proxy :: Proxy PartialTag) -- > {-# INLINE partial #-} -- > -- > -- Define your functions using the Partial class. -- > head :: Partial => [a] -> a -- > head (x:xs) = x ------------------------------------------------------------------------------- module Type.Class.Nullary ( Tag, unsafeTag, Proxy(..) -- re-exported for convenience ) where import Data.Proxy ( Proxy(..) ) import Unsafe.Coerce ( unsafeCoerce ) -- | Class for declaring tagged nullary instances. See module description. class Tag t -- The evil. newtype MagicTag t r = MagicTag (Tag t => r) -- | Unsafely cast off the Tag constraint. This should only -- be used at the "top-level" of an application. In practice, -- specializations of this should be provided, e.g. unsafeUnsafe. -- This uses the same evil as Data.Reflect. unsafeTag :: forall r t. Proxy t -> (Tag t => r) -> r unsafeTag Proxy f = unsafeCoerce (MagicTag f :: MagicTag t r) () {-# INLINE unsafeTag #-}