Skip to content

Commit 496abd4

Browse files
Merge pull request #117 from chrisdone/cd/2026-04-21-entail2
Add entailment for (C a, C b) => C (t a b) for Either and (,)
2 parents 0e2a656 + 58484f9 commit 496abd4

2 files changed

Lines changed: 50 additions & 6 deletions

File tree

examples/15-type-classes.hell

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@ main = do
22
Text.putStrLn (Show.show 123)
33
Text.putStrLn (Show.show Bool.True)
44
Text.putStrLn $ Show.show $ Eq.eq 1 1
5+
Text.putStrLn $ Show.show $ Eq.eq (1,1) (1,1)
56
Text.putStrLn $ Show.show $ Eq.eq [Maybe.Just 1] [Maybe.Just 2]
7+
Text.putStrLn $ Show.show $ Eq.eq [Either.Left 1] [Either.Right "abc"]
68
IO.print [Maybe.Just 1, Maybe.Nothing]
79
IO.print $ Maybe.Just [1] <> Maybe.Nothing
10+
IO.print $ [Either.Left (Maybe.Just 1), Either.Right (Maybe.Just "abc"), Either.Left Maybe.Nothing]
11+
IO.print [Maybe.Just (1, 2), Maybe.Nothing]
812

913
env <- Environment.getEnvironment
1014
Maybe.maybe

src/Hell.hs

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,13 @@ lookupDict rep crep =
792792
Just Type.HRefl <- Type.eqTypeRep (typeRepKind t) (TypeRep @(Type -> Type)),
793793
Just dict <- resolve1 (Type.App crep rep) crep t instances ->
794794
pure dict
795-
-- Cases that look like: Monad (Either (e :: *) (a :: *))
795+
-- Cases that look like: Eq (Either (e :: *) (a :: *))
796+
-- Note: the kinds are limited to this exact specification in the signature above.
797+
| Type.App (Type.App t _) _ <- rep,
798+
Just Type.HRefl <- Type.eqTypeRep (typeRepKind t) (TypeRep @(Type -> Type -> Type)),
799+
Just dict <- resolve2 (Type.App crep rep) crep t instances ->
800+
pure dict
801+
-- Cases that look like: Monad (Either (e :: *))
796802
-- Note: the kinds are limited to this exact specification in the signature above.
797803
| Type.App t _ <- rep,
798804
Just Type.HRefl <- Type.eqTypeRep (typeRepKind t) (TypeRep @(Type -> Type -> Type)),
@@ -820,6 +826,9 @@ newtype D2 c t = D2 (forall f a. Dict (c (t f a)))
820826
-- Entailment, c a => c (t a), E.g. Eq a :- Eq [a]
821827
newtype ED1 c t = ED1 (forall e. c e :- c (t e))
822828

829+
-- Entailment, (c a, c b) => c (t a b), E.g. (Eq a, Eq b) :- Eq (Either a b)
830+
newtype ED2 c t = ED2 (forall e f. (c e, c f) :- c (t e f))
831+
823832
newtype Instances = Instances {getInstances ::Map (SomeTypeRep, SomeTypeRep) Dynamic}
824833

825834
instances :: Instances
@@ -831,6 +840,8 @@ instances =
831840
entail1 @Show @Tree,
832841
entail1 @Show @Maybe,
833842
entail1 @Show @Vector,
843+
entail2 @Show @Either,
844+
entail2 @Show @(,),
834845
instance0 @Show @Int,
835846
instance0 @Show @Integer,
836847
instance0 @Show @Day,
@@ -846,6 +857,8 @@ instances =
846857
entail1 @Eq @[],
847858
entail1 @Eq @Set,
848859
entail1 @Eq @Maybe,
860+
entail2 @Eq @Either,
861+
entail2 @Eq @(,),
849862
entail1 @Eq @Tree,
850863
entail1 @Eq @Vector,
851864
instance0 @Eq @Int,
@@ -862,6 +875,8 @@ instances =
862875
entail1 @Ord @[],
863876
entail1 @Ord @Set,
864877
entail1 @Ord @Maybe,
878+
entail2 @Ord @Either,
879+
entail2 @Ord @(,),
865880
entail1 @Ord @Tree,
866881
entail1 @Ord @Vector,
867882
instance0 @Ord @Int,
@@ -886,6 +901,7 @@ instances =
886901
instance0 @Functor @Tree,
887902
instance0 @Functor @Options.Parser,
888903
instance1 @Functor @Either,
904+
instance1 @Functor @(,), -- Functor (a,)
889905
instance0 @Applicative @IO,
890906
instance0 @Applicative @Maybe,
891907
instance0 @Applicative @[],
@@ -894,11 +910,13 @@ instances =
894910
instance1 @Applicative @Either,
895911
instance0 @Alternative @Options.Parser,
896912
instance0 @Alternative @Maybe,
897-
entail1 @Semigroup @Maybe,
913+
entail1 @Monoid @Maybe,
898914
instance0 @Monoid @Text,
899915
instance1 @Monoid @Vector,
900916
instance2 @Monoid @Options.Mod,
901917
instance1 @Monoid @[],
918+
entail1 @Semigroup @Maybe,
919+
instance2 @Semigroup @Either,
902920
instance2 @Semigroup @Options.Mod,
903921
instance0 @Semigroup @Text,
904922
instance1 @Semigroup @Vector,
@@ -959,6 +977,16 @@ instance2 =
959977
toDyn $ D2 @c @t Dict
960978
)
961979

980+
-- Same as entail1, but for 2-ary types like Either.
981+
entail2 ::
982+
forall {k1} (c :: k1 -> Constraint) (t :: k1 -> k1 -> k1).
983+
((forall a b. (c a, c b) => c (t a b)), Typeable c, Typeable t, Typeable k1) =>
984+
((SomeTypeRep, SomeTypeRep), Dynamic)
985+
entail2 =
986+
( (SomeTypeRep $ typeRep @c, SomeTypeRep $ typeRep @t),
987+
toDyn $ ED2 @c @t (Sub Dict)
988+
)
989+
962990
--------------------------------------------------------------------------------
963991
-- Instance resolution
964992

@@ -1003,11 +1031,23 @@ resolve2 ::
10031031
TypeRep t ->
10041032
Instances ->
10051033
Maybe (Dict (c (t a b)))
1006-
resolve2 _ c t (Instances m) = do
1034+
resolve2 cta c t (Instances m) = do
10071035
Dynamic rep dict <- Map.lookup (SomeTypeRep c, SomeTypeRep t) m
1008-
Type.HRefl <- Type.eqTypeRep rep $ Type.App (Type.App (typeRep @D2) c) t
1009-
let D2 d = dict
1010-
pure d
1036+
(do Type.HRefl <- Type.eqTypeRep rep $ Type.App (Type.App (typeRep @D2) c) t
1037+
let D2 d = dict
1038+
pure d) <|>
1039+
-- When we see e.g. C (T A), where T A and A have the same kind,
1040+
-- we can lookup C A, for the entailment C A, C B :- C (T A B).
1041+
(case cta of
1042+
Type.App _c a@(Type.App (Type.App f a') b') -> do
1043+
Type.HRefl <- Type.eqTypeRep (typeRepKind a') (typeRepKind a)
1044+
Type.HRefl <- Type.eqTypeRep (typeRepKind b') (typeRepKind a)
1045+
Type.HRefl <- Type.eqTypeRep rep $ Type.App (Type.App (typeRep @ED2) c) f
1046+
Dict <- lookupDict a' c
1047+
Dict <- lookupDict b' c
1048+
let ED2 (Sub d) = dict
1049+
pure d
1050+
_ -> Nothing)
10111051

10121052
--------------------------------------------------------------------------------
10131053

0 commit comments

Comments
 (0)