content: {-|
  Module      : Crypto.Lol.Reflects
  Description : Generic interface for reflecting types to values.
  Copyright   : (c) Eric Crockett, 2011-2017
                    Chris Peikert, 2011-2017
  License     : GPL-3
  Maintainer  : ecrockett0@email.com
  Stability   : experimental
  Portability : POSIX
  
  Generic interface for reflecting types to values.
  -}
  
  {-# LANGUAGE AllowAmbiguousTypes   #-}
  {-# LANGUAGE DataKinds             #-}
  {-# LANGUAGE FlexibleContexts      #-}
  {-# LANGUAGE FlexibleInstances     #-}
  {-# LANGUAGE MultiParamTypeClasses #-}
  {-# LANGUAGE NoImplicitPrelude     #-}
  {-# LANGUAGE PolyKinds             #-}
  {-# LANGUAGE ScopedTypeVariables   #-}
  {-# LANGUAGE TypeApplications      #-}
  {-# LANGUAGE UndecidableInstances  #-}
  
  module Crypto.Lol.Reflects
  ( Reflects(..)
  ) where
  
  import Algebra.Ring      as Ring
  import Algebra.ToInteger as ToInteger
  import NumericPrelude
  
  import Crypto.Lol.Factored
  
  import Data.Proxy
  import Data.Reflection
  import Data.Singletons
  import GHC.TypeLits    as TL
  
  -- | Reflection without fundep, and with tagged value. Intended only
  -- for low-level code; build specialized wrappers around it for
  -- specific functionality.
  
  class Reflects a i where
    -- | Reflect the value assiated with the type @a@.
    value :: i
  
  instance (KnownNat a, Ring.C i) => Reflects (a :: TL.Nat) i where
    value = fromIntegral $ natVal (Proxy::Proxy a)
  
  instance (PosC a, ToInteger.C i) => Reflects a i where
    value = posToInt $ fromSing (sing :: Sing a)
  
  instance (BinC a, ToInteger.C i) => Reflects a i where
    value = binToInt $ fromSing (sing :: Sing a)
  
  instance (Prime p, ToInteger.C i) => Reflects p i where
    value = fromIntegral $ valuePrime @p
  
  instance (PPow pp, ToInteger.C i) => Reflects pp i where
    value = fromIntegral $ valuePPow @pp
  
  instance (Fact m, ToInteger.C i) => Reflects m i where
    value = fromIntegral $ valueFact @m
  
  instance (Reifies q i, ToInteger.C i, Ring.C r)
    => Reflects (q :: *) r where
    value = fromIntegral $ reflect (Proxy::Proxy q)
  