fcf-containers-0.8.2: src/Fcf/Data/Reflect.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeInType #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -Wall #-}
{-# OPTIONS_GHC -Werror=incomplete-patterns #-}
{-|
Module : Fcf.Data.Reflect
Description : List helpers / utils
Copyright : (c) gspia 2023-
License : BSD
Maintainer : gspia
= Fcf.Data.Reflect
Helpers to get results from type-level computations into the fromType-level.
-}
--------------------------------------------------------------------------------
module Fcf.Data.Reflect where
import qualified GHC.TypeLits as TL
import GHC.TypeLits (Nat, Symbol, KnownNat, KnownSymbol)
import Data.String (fromString, IsString)
import Data.Proxy
import Data.Typeable (Typeable, typeRep)
import Data.Kind (Type)
import qualified Data.Map as DM
import qualified Data.IntMap.Strict as IMS
import qualified Data.Set as S
-- #if __GLASGOW_HASKELL__ >= 902
-- #endif
import qualified Data.Tree as T
import qualified Fcf.Data.MapC as MC
import qualified Fcf.Data.NatMap as NM
import qualified Fcf.Data.Set as FS
#if __GLASGOW_HASKELL__ >= 902
import qualified Fcf.Data.NewText as FTxt
#endif
import qualified Fcf.Data.Tree as FT
--------------------------------------------------------------------------------
-- | Reflect a list of Nats
--
-- Note that you may also use the KnownVal methods given below.
--
-- This method is taken from
-- https://hackage.haskell.org/package/numhask-array-0.10.1/docs/src/NumHask.Array.Shape.html#natVals
--
-- === __Example__
--
-- > :{
-- afun :: forall n. (n ~ '[1,2,3,4]) => [Int]
-- afun = natVals @n Proxy
-- :}
--
-- > afun
-- [1,2,3,4]
class KnownNats (ns :: [Nat]) where
natVals :: Proxy ns -> [Int]
{-# DEPRECATED KnownNats "Replaced with KnownVal" #-}
instance KnownNats '[] where
natVals _ = []
instance (TL.KnownNat n, KnownNats ns) => KnownNats (n : ns) where
natVals _ = fromInteger (TL.natVal (Proxy @n)) : natVals (Proxy @ns)
--------------------------------------------------------------------------------
class KnownVal val kind where
fromType :: Proxy kind -> val
instance (KnownNat n, Num a) => KnownVal a (n :: Nat) where
fromType _ = fromInteger $ TL.natVal (Proxy @n)
instance KnownVal Bool 'True where fromType _ = True
instance KnownVal Bool 'False where fromType _ = False
instance KnownVal () '() where fromType _ = ()
instance (IsString str, KnownSymbol s) => KnownVal str (s :: Symbol) where
fromType _ = fromString $ TL.symbolVal (Proxy @s)
#if __GLASGOW_HASKELL__ >= 920
instance (TL.KnownChar c) => KnownVal Char c where
fromType _ = TL.charVal (Proxy @c)
#endif
instance (IsString str, Typeable typ) => KnownVal str (typ :: Type) where
fromType = fromString . show . typeRep
#if __GLASGOW_HASKELL__ >= 902
-- | Text instance.
--
-- === __Example__
--
-- > import qualified Data.Text as Txt
-- > :{
-- afun :: forall r. (r ~ 'FTxt.Text "hmm") => Txt.Text
-- afun = fromType (Proxy @r)
-- :}
--
-- > afun
-- "hmm"
instance (IsString str, KnownSymbol sym) => KnownVal str ('FTxt.Text sym)
where
fromType _ = fromType @str (Proxy @sym)
#endif
--------------------------------------------------------------------------------
-- List instances
instance KnownVal [a] '[] where
fromType _ = []
instance (KnownVal val x, KnownVal [val] xs) => KnownVal [val] (x ': xs) where
fromType _ = fromType (Proxy @x) : fromType (Proxy @xs)
--------------------------------------------------------------------------------
-- Trees
--
instance (KnownVal val k, KnownVal (T.Forest val) trees) => KnownVal (T.Tree val) ('FT.Node k trees)
where
fromType _ = T.Node (fromType (Proxy @k)) (fromType (Proxy @trees))
--------------------------------------------------------------------------------
-- NatMaps / IntMaps
--
instance (KnownVal [(Int,val)] pairs) => KnownVal (IMS.IntMap val) ('NM.NatMap pairs)
where
fromType _ = IMS.fromList (fromType (Proxy @pairs))
instance (KnownVal [(Int,val)] pairs) => KnownVal (IMS.IntMap val) (pairs :: [(Nat, val')])
where
fromType _ = IMS.fromList (fromType (Proxy @pairs))
--------------------------------------------------------------------------------
-- Maps
instance (Ord key, KnownVal [(key,val)] pairs) => KnownVal (DM.Map key val) ('MC.MapC pairs)
where
fromType _ = DM.fromList (fromType (Proxy @pairs))
instance (Ord key, KnownVal [(key,val)] pairs) => KnownVal (DM.Map key val) (pairs :: [(key',val')])
where
fromType _ = DM.fromList (fromType (Proxy @pairs))
--------------------------------------------------------------------------------
-- Set
instance (Ord val, KnownVal [val] kind) => KnownVal (S.Set val) ('FS.Set kind)
where
fromType _ = S.fromList (fromType (Proxy @kind))
instance (Ord val, KnownVal [val] kind) => KnownVal (S.Set val) (kind :: [kind'])
where
fromType _ = S.fromList (fromType (Proxy @kind))
--------------------------------------------------------------------------------
-- Either
instance (KnownVal a1 a) => KnownVal (Either a1 b1) ('Left a) where
fromType _ = Left (fromType @a1 (Proxy @a))
instance (KnownVal b1 b) => KnownVal (Either a1 b1) ('Right b) where
fromType _ = Right (fromType @b1 (Proxy @b))
--------------------------------------------------------------------------------
-- Maybe
instance (KnownVal a1 a) => KnownVal (Maybe a1) ('Just a) where
fromType _ = Just (fromType @a1 (Proxy @a))
instance KnownVal (Maybe a1) 'Nothing where
fromType _ = Nothing
--------------------------------------------------------------------------------
-- Tuples
instance (KnownVal a1 a, KnownVal b1 b) => KnownVal (a1,b1) '(a,b) where
fromType _ = (fromType @a1 (Proxy @a), fromType @b1 (Proxy @b))
instance (KnownVal a1 a, KnownVal b1 b, KnownVal c1 c) => KnownVal (a1,b1,c1) '(a,b,c) where
fromType _ = (fromType @a1 (Proxy @a), fromType @b1 (Proxy @b), fromType @c1 (Proxy @c))
instance (KnownVal a1 a, KnownVal b1 b, KnownVal c1 c, KnownVal d1 d) => KnownVal (a1,b1,c1,d1) '(a,b,c,d) where
fromType _ = (fromType @a1 (Proxy @a), fromType @b1 (Proxy @b), fromType @c1 (Proxy @c), fromType @d1 (Proxy @d))
instance (KnownVal a1 a, KnownVal b1 b, KnownVal c1 c, KnownVal d1 d, KnownVal e1 e) => KnownVal (a1,b1,c1,d1,e1) '(a,b,c,d,e) where
fromType _ = (fromType @a1 (Proxy @a), fromType @b1 (Proxy @b), fromType @c1 (Proxy @c), fromType @d1 (Proxy @d), fromType @e1 (Proxy @e))
--------------------------------------------------------------------------------
-- ErrorMessage from GHC.TypeLits
instance (IsString str, KnownSymbol sym) => KnownVal str ('TL.Text sym) where
fromType _ = fromType @str (Proxy @sym)
instance (IsString str, Typeable typ) => KnownVal str ('TL.ShowType typ) where
fromType _ = fromString $ show $ typeRep (Proxy @typ)
instance (IsString str, KnownVal str err1, KnownVal str err2, Semigroup str) => KnownVal str (err1 'TL.:<>: err2) where
fromType _ = fromType (Proxy @err1) <> fromType (Proxy @err2)
instance (IsString str, KnownVal str err1, KnownVal str err2, Semigroup str) => KnownVal str (err1 'TL.:$$: err2) where
fromType _ = fromType (Proxy @err1) <> fromString "\n" <> fromType (Proxy @err2)