Proxy is a mysterious type residing in Data.Proxy module. The definition of Proxy tells nothing about its nature.
-- | A concrete, poly-kinded proxy type
data Proxy t = ProxyThe documentation of Proxy says two hints. It is a (1) concrete and (2) poly-kinded proxy type.
Poly-kinded
The kind of Proxy is forall k. k -> *.
λ> :k Proxy
Proxy :: k -> *Here k is poly-kinded so we can pass types of any kind to Proxy.
- Proxy Charwhere- kis- *.
- Proxy (,)where- kis- * -> *
- Proxy Showwhere- kis- * -> Constraint
- Proxy Monadwhere- kis- (* -> *) -> Constraint
Concrete value
In Haskell, we can create a value of any type we want by annotating undefined with the type.
λ> let p = undefined :: IntHowever, we can’t use this trick if the kind of the type is not *, For example, we can’t annotate undefined with type (,) because its kind is * -> * -> *.
λ> let q = undefined :: (,)
<interactive>:4:22: error:
    • Expecting two more arguments to ‘(,)’
      Expected a type, but ‘(,)’ has kind ‘* -> * -> *’
    • In an expression type signature: (,)
      In the expression: undefined :: (,)
      In an equation for ‘q’: q = undefined :: (,)Proxy lets us to overcome this limitation. We can create a proxy value representing the type by annotating Proxy data constructor.
λ> import Data.Proxy
λ> let p = Proxy :: Proxy (,)
λ> :t p
p :: Proxy (,)We can think of Proxy :: Proxy (,) as a reified value of the type (,).
Type Application
The read/show problem below is ill-typed because of ambiguity.
f :: String -> String
f s = show (read s)We can fix this issue by explicitly passing the type as a value argument. As you can see the wild card pattern _, the value is not used anywhere in the definition of f. Only its type is used.
f :: forall proxy a. (Read a, Show a) => proxy a -> String -> String
f _ = (show :: a -> String) . readλ> f (Proxy :: Proxy Int) "3"
"3"As a side note, TypeApplications extension introduced in GHC 8 provides an alternative way to fix this.
Typeable
Another application of Proxy is Typeable. Before kind polymorphism was introduced in GHC, there was a lot of code duplication in the way Typeable is implemented because t can represent only a specific kind.
class Typeable (t :: *) where
  typeOf :: t -> TypeRep
class Typeable1 (t :: * -> *) where
  typeOf1 :: t a -> TypeRep
class Typeable2 (t :: * -> * -> *) where
  typeOf2 :: t a b -> TypeRepProxy allows us to merge all these classes into one:
class Typeable t where
  typeOf :: Proxy t -> TypeRep
instance Typeable Int  where typeOf _ = TypeRep
instance Typeable []   where typeOf _ = TypeRepOther use cases of Proxy
- json-schema uses Proxyto obtain the JSON representation for the given type.
class JSONSchema a where
  schema :: Proxy a -> Schema- Edward Kmett’s reflection package shows an advanced usage of Proxy. Austin Seipp’s Reflecting values to types and back explains how to reify arbitrary terms into types that can be reflected back into terms.