Skip to content

Commit fc2ec64

Browse files
committed
Now with an EverythingIsApplied constraint
To help with silently not overriding anything
1 parent 075c8eb commit fc2ec64

File tree

3 files changed

+27
-23
lines changed

3 files changed

+27
-23
lines changed

src/HedgehogExample.hs

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,20 @@ import V2
99
import Data.Diverse
1010

1111
newtype Name = Name Text
12-
newtype Address = Address Text
1312
newtype Email = Email Text
1413

1514
data Person = Person
1615
{ _name :: Name
17-
, _address :: Address
1816
, _email :: Email
1917
}
2018

2119
data Company = Company
2220
{ _employees :: [Person]
23-
, _ceo :: Person }
21+
}
2422

2523
instance MonadGen m => DefaultRecipe Identity (m Name) where
2624
type DefaultRecipeDeps Identity (m Name) = '[]
27-
def = pureRecipe $ do
28-
name <- text (linear 3 20) unicode
29-
pure $ Name name
30-
31-
instance MonadGen m => DefaultRecipe Identity (m Address) where
32-
type DefaultRecipeDeps Identity (m Address) = '[]
33-
def = pureRecipe $ do
34-
name <- text (linear 3 20) unicode
35-
pure $ Address name
25+
def = pureRecipe $ Name <$> text (linear 3 20) unicode
3626

3727
instance MonadGen m => DefaultRecipe Identity (m Email) where
3828
type DefaultRecipeDeps Identity (m Email) = '[]
@@ -42,28 +32,25 @@ instance MonadGen m => DefaultRecipe Identity (m Email) where
4232
pure $ Email $ (user <> "@" <> host)
4333

4434
instance MonadGen m => DefaultRecipe Identity (m Person) where
45-
type DefaultRecipeDeps Identity (m Person) = '[m Name, m Address, m Email]
35+
type DefaultRecipeDeps Identity (m Person) = '[m Name, m Email]
4636
def = Recipe $ \deps -> pure $ do
4737
name <- grab deps
48-
address <- grab deps
4938
email <- grab deps
50-
pure $ Person name address email
39+
pure $ Person name email
5140

5241
instance MonadGen m => DefaultRecipe Identity (m Company) where
5342
type DefaultRecipeDeps Identity (m Company) = '[m Person]
5443
def = Recipe $ \deps -> pure $ do
55-
ceo <- grab deps
5644
employees <- Gen.list (linear 3 10) (grab deps)
57-
pure $ Company employees ceo
45+
pure $ Company employees
5846

5947
regularGen :: MonadGen m => m Company
6048
regularGen = runIdentity $ finish nil
6149

6250
largeCompanyGen' :: forall (m :: * -> *). MonadGen m => Recipe Identity (m Company) '[m Person]
6351
largeCompanyGen' = Recipe $ \deps -> pure $ do
64-
ceo <- grab deps
6552
employees <- Gen.list (linear 100 1000) (grab deps)
66-
pure $ Company employees ceo
53+
pure $ Company employees
6754

6855
largeCompanyGen :: forall m. MonadGen m => (m Company)
6956
largeCompanyGen = runIdentity $ finish (largeCompanyGen' @m ./ nil) -- TODO why is this annotation required?

src/Tests.hs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,7 @@ c5 = finish nil
5050

5151
rc5 :: Identity M5
5252
rc5 = finish (r5 ./ nil)
53+
54+
-- Should fail with "not everything is applied"
55+
-- rc4fail :: Identity M4
56+
-- rc4fail = finish (r5 ./ nil)

src/V2.hs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import qualified Data.Sequence as S
1313
import Data.Diverse.Many.Internal (Many(..))
1414
import Unsafe.Coerce
1515
import Numbers
16-
-- import GHC.TypeLits as Lits
16+
import GHC.TypeLits as Lits
1717

1818
pureRecipe :: Applicative effect => target -> Recipe effect target '[]
1919
pureRecipe target = Recipe $ \_ -> pure target
@@ -120,13 +120,28 @@ instance forall effect target book state.
120120
(s2r, deps) :: (Many state, Many (RecipeDeps effect target book)) <- s2
121121
(res s2r deps) :: effect (Many state, target)
122122

123-
finish :: forall target (effect:: * -> *) (book :: [*]) (store :: [*]).
123+
type family Contains (target :: *) (store :: [*]) :: Bool where
124+
Contains target (target ': t) = True
125+
Contains target (h ': t) = Contains target t
126+
Contains target '[] = False
127+
128+
type family EverythingIsAppliedTypeError (bool :: Bool) (s :: Type) (b :: [Type]) :: Constraint where
129+
EverythingIsAppliedTypeError True s b = ()
130+
EverythingIsAppliedTypeError False s b = TypeError ('Text "The type " ':<>: ShowType s ':<>: 'Text " is not overriding anything in " ':<>: ShowType b)
131+
132+
type family EverythingIsApplied (effect :: * -> *) target (book :: [*]) (store :: [*]) :: Constraint where
133+
EverythingIsApplied effect target ((Recipe effect head _) ': tBook) store = (EverythingIsAppliedTypeError (Contains head store) head store, EverythingIsApplied effect target tBook store)
134+
EverythingIsApplied effect target (head ': tBook) store = TypeError ('Text "The type " ':<>: ShowType head ':<>: 'Text " is not a Recipe")
135+
EverythingIsApplied effect target '[] store = ()
136+
137+
finish :: forall (effect :: * -> *) target (book :: [*]) (store :: [*]).
124138
( store ~ (LiftMaybe (Nub (RecipeDepsRec effect target book (RecipeDeps effect target book))))
125139
, ToS (ListLen (EmptyStore effect target book))
126140
, HasRecipe effect target book
127141
, Monad effect
128142
, (SubSelect effect book (RecipeDeps effect target book) store)
129143
, (UniqueMember (Maybe target) store)
144+
, EverythingIsApplied effect target book (Nub (RecipeDepsRec effect target book (RecipeDeps effect target book)))
130145
) =>
131146
Many book -> effect target
132147
finish book = do
@@ -136,8 +151,6 @@ finish book = do
136151
(_, target) <- cook book store (Proxy @target)
137152
pure target
138153

139-
-- test
140-
141154
class DefaultRecipe (effect :: * -> *) target where
142155
type DefaultRecipeDeps effect target :: [*]
143156
def :: Recipe effect target (DefaultRecipeDeps effect target)

0 commit comments

Comments
 (0)