singletons-2.4: src/Data/Singletons/ShowSing.hs
{-# LANGUAGE EmptyCase #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeInType #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wno-orphans #-}
-----------------------------------------------------------------------------
-- |
-- Module : Data.Singletons.ShowSing
-- Copyright : (C) 2017 Ryan Scott
-- License : BSD-style (see LICENSE)
-- Maintainer : Richard Eisenberg (rae@cs.brynmawr.edu)
-- Stability : experimental
-- Portability : non-portable
--
-- Defines the class 'ShowSing', allowing for conversion of 'Sing' values to
-- readable 'String's.
--
----------------------------------------------------------------------------
module Data.Singletons.ShowSing (
-- * The 'ShowSing' class
ShowSing(..),
) where
import Data.Singletons.Internal
import Data.Singletons.Prelude.Instances
import Data.Singletons.Single
import Data.Singletons.TypeLits.Internal
import Data.Singletons.Util
import GHC.Show (appPrec, appPrec1)
import GHC.TypeLits (symbolVal)
import qualified GHC.TypeNats as TN (natVal)
----------------------------------------------------------------------
---- ShowSing --------------------------------------------------------
----------------------------------------------------------------------
-- | Members of the 'ShowSing' kind class can have their 'Sing' values
-- converted to 'String's in a fashion similar to that of the 'Show' class.
-- (In fact, this class only exists because one cannot write 'Show' instances
-- for 'Sing's of the form
-- @instance (forall z. Show (Sing (z :: k))) => Show (Sing (x :: [k]))@.)
--
-- This class should not be confused with the promoted or singled versions of
-- 'Show' from "Data.Singletons.Prelude.Show" (@PShow@ and @SShow@, respectively).
-- The output of 'ShowSing' is intended to reflect the singleton type, whereas
-- the output of @PShow@ and @SShow@ reflects the original type. That is, showing
-- @SFalse@ with 'ShowSing' would yield @\"SFalse\"@, whereas @PShow@ and @SShow@
-- would yield @\"False\"@.
--
-- Instances of this class are generated alongside singleton definitions for
-- datatypes that derive a 'Show' instance. Moreover, having a 'ShowSing'
-- instances makes it simple to define a 'Show' instance. For instance:
--
-- @
-- instance 'ShowSing' a => 'ShowSing' [a] where
-- 'showsSingPrec' = ...
-- instance 'ShowSing' a => 'Show' ('Sing' (x :: [a])) where
-- 'showsPrec' = 'showsSingPrec'
-- @
--
-- As a result, singleton definitions for datatypes that derive a 'Show'
-- instance also get a 'Show' instance for the singleton type as well
-- (in addition to promoted and singled 'Show' instances).
--
-- To recap: 'singletons' will give you all of these for a datatype that derives
-- a 'Show' instance:
--
-- * A promoted (@PShow@) instance
-- * A singled (@SShow@) instance
-- * A 'ShowSing' instance for the singleton type
-- * A 'Show' instance for the singleton type
--
-- What a bargain!
class ShowSing k where
-- | @'showsSingPrec' p s@ convert a 'Sing' value @p@ to a readable 'String'
-- with precedence @p@.
showsSingPrec :: Int -> Sing (a :: k) -> ShowS
------------------------------------------------------------
-- TypeLits instances
------------------------------------------------------------
-- These are a bit special because the singleton constructor does not uniquely
-- determine the type being used in the constructor's return type (e.g., all Nats
-- have the same singleton constructor, SNat). To compensate for this, we display
-- the type being used using visible type application. (Thanks to @cumber on #179
-- for suggesting this implementation.)
instance ShowSing Nat where
showsSingPrec p n@SNat
= showParen (p > appPrec)
( showString "SNat @"
. showsPrec appPrec1 (TN.natVal n)
)
instance Show (SNat n) where
showsPrec = showsSingPrec
instance ShowSing Symbol where
showsSingPrec p s@SSym
= showParen (p > appPrec)
( showString "SSym @"
. showsPrec appPrec1 (symbolVal s)
)
instance Show (SSymbol s) where
showsPrec = showsSingPrec
------------------------------------------------------------
-- Template Haskell-generated instances
------------------------------------------------------------
$(showSingInstances basicTypes)