on master help sign in
shift to using deriving-via for atoms
commit0b3434a9f79702cce4a1a6008018b2ca69b71287 authorMark Wotton <mwotton@gmail.com> dateFri 27 Nov 2020, 16:03 (6 years ago) parent1f3a834
3 files changed+80−6
src/Roboservant/Types/BuildFrom.hs+39 src/Roboservant/Types/Internal.hs+33 test/Spec.hs+8−6
src/Roboservant/Types/BuildFrom.hsnew file+39
@@ -0,0 +1,39 @@
1+{-# LANGUAGE DefaultSignatures #-}
2+{-# LANGUAGE DerivingStrategies #-}
3+{-# LANGUAGE ScopedTypeVariables #-}
4+{-# LANGUAGE TypeApplications #-}
5+{-# LANGUAGE TypeFamilies #-}
6+{-# LANGUAGE StandaloneDeriving #-}
7+{-# LANGUAGE DerivingVia #-}
8+
9+
10+
11+module Roboservant.Types.BuildFrom where
12+
13+import Data.List.NonEmpty (NonEmpty(..))
14+import qualified Data.List.NonEmpty as NEL
15+import Data.Typeable (Typeable)
16+import qualified Data.Dependent.Map as DM
17+import qualified Type.Reflection as R
18+import Data.Kind
19+import Roboservant.Types.Internal
20+
21+class Typeable x => BuildFrom (x :: Type) where
22+ buildFrom :: Stash -> Maybe (StashValue x)
23+
24+-- | this is a little esoteric: basically, we're always going to use this with
25+-- deriving-via, so we need to look up the underlying `x` and then wrap it in Atom.
26+instance Typeable x => BuildFrom (Atom x) where
27+ buildFrom = fmap (fmap Atom) <$> DM.lookup R.typeRep . getStash
28+
29+deriving via (Atom Bool) instance BuildFrom Bool
30+
31+instance (Typeable x, BuildFrom x) => BuildFrom (Maybe x) where
32+ buildFrom dict = Just options
33+ where options :: StashValue (Maybe x)
34+ options = StashValue $
35+ ([],Nothing) :|
36+ (maybe [] (NEL.toList . getStashValue . fmap Just) $ buildFrom @x dict
37+ )
38+-- instance (BuildFrom a) => BuildFrom [a] -- where
39+ --breakdown x = toDyn x :| mconcat (map (NEL.toList . breakdown) x)
src/Roboservant/Types/Internal.hsnew file+33
@@ -0,0 +1,33 @@
1+{-# LANGUAGE DeriveFunctor #-}
2+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3+
4+module Roboservant.Types.Internal where
5+
6+import Data.List.NonEmpty (NonEmpty(..))
7+import qualified Data.Map.Strict as Map
8+import qualified Data.Dependent.Map as DM
9+import Data.Dependent.Map (DMap)
10+import qualified Type.Reflection as R
11+import Data.Dependent.Sum
12+
13+data Provenance
14+ = Provenance R.SomeTypeRep Int
15+ deriving (Show,Eq)
16+
17+newtype StashValue a = StashValue { getStashValue :: NonEmpty ([Provenance], a) }
18+ deriving (Functor, Show)
19+
20+-- wrap in newtype to give a custom Show instance, since the normal
21+-- instance for DMap is not happy since StashValue needs Show a to show
22+newtype Stash = Stash { getStash :: DMap R.TypeRep StashValue }
23+ deriving (Semigroup, Monoid)
24+
25+instance Show Stash where
26+ showsPrec i (Stash x) = showsPrec i $
27+ Map.fromList . map (\(tr :=> StashValue vs) -> (R.SomeTypeRep tr, fmap fst vs)) $ DM.toList x
28+
29+-- | Can't be built up from parts, can't be broken down further.
30+newtype Atom x = Atom { unAtom :: x }
31+
32+-- | can be broken down and built up from generic pieces
33+newtype Compound x = Compound { unCompound :: x }
test/Spec.hs+8−6
@@ -1,6 +1,10 @@
11
22{-# LANGUAGE OverloadedStrings #-}
33{-# LANGUAGE TypeApplications #-}
4+{-# LANGUAGE DerivingVia #-}
5+{-# LANGUAGE StandaloneDeriving #-}
6+
7+
48{-# OPTIONS_GHC -fno-warn-orphans #-}
59import qualified Foo
610import qualified Seeded
@@ -67,10 +71,8 @@ instance RS.Breakdown Foo.Foo where
6771instance RS.Breakdown Headers.Foo where
6872 breakdown = pure . toDyn
6973
70−instance RS.BuildFrom Foo.Foo
71−
72−instance RS.BuildFrom Headers.Foo
73−
74−instance RS.BuildFrom Seeded.Seed
7574
76−instance RS.BuildFrom Void
75+deriving via (RS.Atom Void) instance RS.BuildFrom Void
76+deriving via (RS.Atom Foo.Foo) instance RS.BuildFrom Foo.Foo
77+deriving via (RS.Atom Headers.Foo) instance RS.BuildFrom Headers.Foo
78+deriving via (RS.Atom Seeded.Seed) instance RS.BuildFrom Seeded.Seed