| 
 Copyright   :   ( C ) 2018      , QBayLogic B.V. 
 License     :   BSD2 ( see the file LICENSE ) 
 Maintainer :     <  > 

 Hidden arguments 

Copyright  :  (C) 2018     , QBayLogic B.V.
License    :  BSD2 (see the file LICENSE)
Maintainer :  Christiaan Baaij <>

Hidden arguments
-}

# LANGUAGE AllowAmbiguousTypes     #
{-# LANGUAGE ConstraintKinds        #-}
{-# LANGUAGE DataKinds              #-}
# LANGUAGE FunctionalDependencies #
# LANGUAGE KindSignatures          #
# LANGUAGE MultiParamTypeClasses   #
{-# LANGUAGE Rank2Types             #-}
{-# LANGUAGE ScopedTypeVariables    #-}
# LANGUAGE TypeApplications        #

# LANGUAGE Trustworthy #

module Clash.Hidden
  ( Hidden
  , expose
  -- * OverloadedLabels
  , fromLabel
  )
where

import qualified GHC.Classes
import GHC.TypeLits
import Unsafe.Coerce

-- | A value reflected to, or /hiding/ at, the /Constraint/ level
--
-- e.g. a function:
--
-- @
-- f :: Hidden "foo" Int
--   => Bool
--   -> Int
-- f = ...
-- @
--
  has a /normal/ argument of type @Bool@ , and a /hidden/ argument called \"foo\ "
  of type @Int@. In order to apply the @Int@ argument we have to use the
-- 'expose' function, so that the /hidden/ argument becomes a normal argument
-- again.
--
-- === __Original implementation__
--
-- 'Hidden' used to be implemented by:
--
-- @
-- class Hidden (x :: Symbol) a | x -> a where
--   hidden :: a
-- @
--
-- which is equivalent to /IP/, except that /IP/ has magic inference rules
  bestowed by GHC so that there 's never any ambiguity . We need these magic
-- inference rules so we don't end up in type inference absurdity where asking
-- for the type of an type-annotated value results in a /no-instance-in-scope/
-- error.
type Hidden (x :: Symbol) a = GHC.Classes.IP x a

newtype Secret x a r = Secret (Hidden x a => r)

-- | Expose a 'Hidden' argument so that it can be applied normally, e.g.
--
-- @
-- f :: Hidden "foo" Int
--   => Bool
--   -> Int
-- f = ...
--
-- g :: Int -> Bool -> Int
  g = ' expose '  " f
-- @
expose
  :: forall x a r
   . (Hidden x a => r)
  -- ^ Function with a 'Hidden' argument
  -> (a -> r)
  -- ^ Function with the 'Hidden' argument exposed
expose k = unsafeCoerce (Secret @x @a @r k)
{-# INLINE expose #-}

-- | Using /-XOverloadedLabels/ and /-XRebindableSyntax/, we can turn any
-- value into a /hidden/ argument using the @#foo@ notation, e.g.:
--
-- @
-- f :: Int -> Bool -> Int
-- f = ...
--
-- g :: Hidden "foo" Bool
--   => Int -> Int
-- g i = f i #foo
-- @
fromLabel :: forall x a . Hidden x a => a
fromLabel = GHC.Classes.ip @x
{-# INLINE fromLabel #-}

# LANGUAGE ConstraintKinds        #
# LANGUAGE DataKinds              #
# LANGUAGE Rank2Types             #
# LANGUAGE ScopedTypeVariables    #
 * OverloadedLabels
 | A value reflected to, or /hiding/ at, the /Constraint/ level

 e.g. a function:

 @
 f :: Hidden "foo" Int
   => Bool
   -> Int
 f = ...
 @

 'expose' function, so that the /hidden/ argument becomes a normal argument
 again.

 === __Original implementation__

 'Hidden' used to be implemented by:

 @
 class Hidden (x :: Symbol) a | x -> a where
   hidden :: a
 @

 which is equivalent to /IP/, except that /IP/ has magic inference rules
 inference rules so we don't end up in type inference absurdity where asking
 for the type of an type-annotated value results in a /no-instance-in-scope/
 error.
 | Expose a 'Hidden' argument so that it can be applied normally, e.g.

 @
 f :: Hidden "foo" Int
   => Bool
   -> Int
 f = ...

 g :: Int -> Bool -> Int
 @
 ^ Function with a 'Hidden' argument
 ^ Function with the 'Hidden' argument exposed
# INLINE expose #
 | Using /-XOverloadedLabels/ and /-XRebindableSyntax/, we can turn any
 value into a /hidden/ argument using the @#foo@ notation, e.g.:

 @
 f :: Int -> Bool -> Int
 f = ...

 g :: Hidden "foo" Bool
   => Int -> Int
 g i = f i #foo
 @
# INLINE fromLabel #
| 
 Copyright   :   ( C ) 2018      , QBayLogic B.V. 
 License     :   BSD2 ( see the file LICENSE ) 
 Maintainer :     <  > 

 Hidden arguments 

Copyright  :  (C) 2018     , QBayLogic B.V.
License    :  BSD2 (see the file LICENSE)
Maintainer :  Christiaan Baaij <>

Hidden arguments
-}

# LANGUAGE AllowAmbiguousTypes     #
# LANGUAGE FunctionalDependencies #
# LANGUAGE KindSignatures          #
# LANGUAGE MultiParamTypeClasses   #
# LANGUAGE TypeApplications        #

# LANGUAGE Trustworthy #

module Clash.Hidden
  ( Hidden
  , expose
  , fromLabel
  )
where

import qualified GHC.Classes
import GHC.TypeLits
import Unsafe.Coerce

  has a /normal/ argument of type @Bool@ , and a /hidden/ argument called \"foo\ "
  of type @Int@. In order to apply the @Int@ argument we have to use the
  bestowed by GHC so that there 's never any ambiguity . We need these magic
type Hidden (x :: Symbol) a = GHC.Classes.IP x a

newtype Secret x a r = Secret (Hidden x a => r)

  g = ' expose '  " f
expose
  :: forall x a r
   . (Hidden x a => r)
  -> (a -> r)
expose k = unsafeCoerce (Secret @x @a @r k)

fromLabel :: forall x a . Hidden x a => a
fromLabel = GHC.Classes.ip @x
