fcf-containers-0.8.1: 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 qualified Data.Map.Strict as MS
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.Core as C (Eval)
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
--------------------------------------------------------------------------------
-- For the doctests:
-- $setup
-- >>> import qualified GHC.TypeLits as TL
-- >>> import Fcf.Data.Nat
--------------------------------------------------------------------------------
-- | 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]
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 (IsString str, KnownSymbol s) => KnownVal str (s :: Symbol )where
fromType _ = fromString $ TL.symbolVal (Proxy @s)
#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 _ = fromString $ fromType $ Proxy @sym
#endif
--------------------------------------------------------------------------------
-- List instances
instance KnownVal [a] '[] where
fromType _ = []
instance (KnownVal typ x, KnownVal [typ] xs) => KnownVal [typ] (x ': xs) where
fromType _ = fromType (Proxy @x) : fromType (Proxy @xs)
--------------------------------------------------------------------------------
-- Trees
--
instance (KnownVal typ k, KnownVal (T.Forest typ) trees) => KnownVal (T.Tree typ) ('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))
--------------------------------------------------------------------------------
-- Maps
instance (Ord key, KnownVal [(key,val)] pairs) => KnownVal (DM.Map key val) ('MC.MapC pairs)
where
fromType _ = DM.fromList (fromType (Proxy @pairs))
--------------------------------------------------------------------------------
-- Set
instance (Ord typ, KnownVal [typ] kind) => KnownVal (S.Set typ) ('FS.Set 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))