module Generics.SOP.Skeleton (
Skeleton(..)
) where
import Control.Exception
import Data.Text (Text)
import Generics.SOP
class Skeleton a where
default skeleton :: (Generic a, HasDatatypeInfo a, Code a ~ '[xs], All Skeleton xs) => a
skeleton :: a
skeleton = gskeleton
instance Skeleton [a] where skeleton = undefined
instance Skeleton (Maybe a) where skeleton = undefined
instance Skeleton Int where skeleton = undefined
instance Skeleton Double where skeleton = undefined
instance Skeleton Rational where skeleton = undefined
instance Skeleton Bool where skeleton = undefined
instance Skeleton Text where skeleton = undefined
gskeleton :: forall a xs. (Generic a, HasDatatypeInfo a, Code a ~ '[xs], All Skeleton xs) => a
gskeleton = to $ gskeleton' (datatypeInfo (Proxy :: Proxy a))
gskeleton' :: All Skeleton xs => DatatypeInfo '[xs] -> SOP I '[xs]
gskeleton' (ADT _ _ (c :* Nil)) = gskeletonFor c
gskeleton' (Newtype _ _ c) = gskeletonFor c
#if __GLASGOW_HASKELL__ < 800
gskeleton' _ = error "inaccessible"
#endif
gskeletonFor :: All Skeleton xs => ConstructorInfo xs -> SOP I '[xs]
gskeletonFor (Constructor _) = SOP $ Z $ spineWithNames (hpure (K ""))
gskeletonFor (Infix _ _ _) = SOP $ Z $ spineWithNames (hpure (K ""))
gskeletonFor (Record _ fs) = SOP $ Z $ spineWithNames (hliftA sfieldName fs)
where
sfieldName :: FieldInfo a -> K String a
sfieldName (FieldInfo n) = K n
spineWithNames :: (All Skeleton xs, SListI xs) => NP (K String) xs -> NP I xs
spineWithNames = hcliftA ps aux
where
aux :: Skeleton a => K String a -> I a
aux (K "") = I $ skeleton
aux (K n) = I $ mapException (addFieldName n) skeleton
addFieldName :: FieldName -> ErrorCall -> ErrorCall
#if MIN_VERSION_base(4,9,0)
addFieldName n (ErrorCallWithLocation str loc) =
ErrorCallWithLocation (n ++ ": " ++ str) loc
#else
addFieldName n (ErrorCall str) = ErrorCall (n ++ ": " ++ str)
#endif
ps :: Proxy Skeleton
ps = Proxy