summaryrefslogtreecommitdiff
path: root/testsuite/tests/polykinds/T11480b.hs
blob: 0ec19753a05db15df05fb5b30cf3f8ba57174ab5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
{-# language KindSignatures #-}
{-# language PolyKinds #-}
{-# language DataKinds #-}
{-# language TypeFamilies #-}
{-# language RankNTypes #-}
{-# language NoImplicitPrelude #-}
{-# language FlexibleContexts #-}
{-# language MultiParamTypeClasses #-}
{-# language GADTs #-}
{-# language ConstraintKinds #-}
{-# language FlexibleInstances #-}
{-# language TypeOperators #-}
{-# language ScopedTypeVariables #-}
{-# language DefaultSignatures #-}
{-# language FunctionalDependencies #-}
{-# language UndecidableSuperClasses #-}

-- This code, supplied by Edward Kmett, uses UndecidableSuperClasses along
-- with a bunch of other stuff, so it's a useful stress test.
-- See #11480 comment:12.

module T11480b where

import Data.Kind (Constraint, Type)
import Data.Type.Equality as Equality
import Data.Type.Coercion as Coercion
import qualified Prelude
import Prelude (Either(..))

newtype Y (p :: i -> j -> Type) (a :: j) (b :: i) = Y { getY :: p b a }

type family Op (p :: i -> j -> Type) :: j -> i -> Type where
  Op (Y p) = p
  Op p = Y p

class Vacuous (p :: i -> i -> Type) (a :: i)
instance Vacuous p a

data Dict (p :: Constraint) where
  Dict :: p => Dict p

class Functor (Op p) (Nat p (->)) p => Category (p :: i -> i -> Type) where
  type Ob p :: i -> Constraint
  type Ob p = Vacuous p

  id :: Ob p a => p a a
  (.) :: p b c -> p a b -> p a c

  source :: p a b -> Dict (Ob p a)
  default source :: (Ob p ~ Vacuous p) => p a b -> Dict (Ob p a)
  source _ = Dict

  target :: p a b -> Dict (Ob p b)
  default target :: (Ob p ~ Vacuous p) => p a b -> Dict (Ob p b)
  target _ = Dict

  op :: p b a -> Op p a b
  default op :: Op p ~ Y p => p b a -> Op p a b
  op = Y

  unop :: Op p b a -> p a b
  default unop :: Op p ~ Y p => Op p b a -> p a b
  unop = getY

class (Category p, Category q) =>
      Functor (p :: i -> i -> Type)
              (q :: j -> j -> Type)
              (f :: i -> j) | f -> p q where
  fmap :: p a b -> q (f a) (f b)

data Nat (p :: i -> i -> Type)
         (q :: j -> j -> Type) (f :: i -> j) (g :: i -> j) where
  Nat :: (Functor p q f, Functor p q g) =>
         { runNat :: forall a. Ob p a => q (f a) (g a) } -> Nat p q f g

instance (Category p, Category q) => Category (Nat p q) where
  type Ob (Nat p q) = Functor p q
  id = Nat id1 where
    id1 :: forall f x. (Functor p q f, Ob p x) => q (f x) (f x)
    id1 = id \\ (ob :: Ob p x :- Ob q (f x))
  Nat f . Nat g = Nat (f . g)
  source Nat{} = Dict
  target Nat{} = Dict

ob :: forall p q f a. Functor p q f => Ob p a :- Ob q (f a)
ob = Sub (case source (fmap (id :: p a a) :: q (f a) (f a)) of Dict -> Dict)

instance (Category p, Category q) =>
         Functor (Y (Nat p q)) (Nat (Nat p q) (->)) (Nat p q) where
  fmap (Y f) = Nat (. f)

instance (Category p, Category q) => Functor (Nat p q) (->) (Nat p q f) where
  fmap = (.)

contramap :: Functor p q f => Op p b a -> q (f a) (f b)
contramap = fmap . unop

instance Category (->) where
  id = Prelude.id
  (.) = (Prelude..)

instance Functor (->) (->) ((->) e) where
  fmap = (.)

instance Functor (Y (->)) (Nat (->) (->)) (->) where
  fmap (Y f) = Nat (. f)

instance (Category p, Op p ~ Y p) => Category (Y p) where
  type Ob (Y p) = Ob p
  id = Y id
  Y f . Y g = Y (g . f)
  source (Y f) = target f
  target (Y f) = source f
  unop = Y
  op = getY

instance (Category p, Op p ~ Y p) => Functor (Y p) (->) (Y p a) where
  fmap = (.)

instance (Category p, Op p ~ Y p) => Functor p (Nat (Y p) (->)) (Y p) where
  fmap f = Nat (. Y f)

--------------------------------------------------------------------------------
-- * Constraints
--------------------------------------------------------------------------------

infixl 1 \\ -- comment required for cpp
(\\) :: a => (b => r) -> (a :- b) -> r
r \\ Sub Dict = r

newtype p :- q = Sub (p => Dict q)

instance Functor (:-) (->) Dict where
  fmap p Dict = case p of
    Sub q -> q

instance Category (:-) where
  id = Sub Dict
  f . g = Sub (Dict \\ f \\ g)

instance Functor (:-) (->) ((:-) e) where
  fmap = (.)

instance Functor (Y (:-)) (Nat (:-) (->)) (:-) where
  fmap (Y f) = Nat (. f)

--------------------------------------------------------------------------------
-- * Common Functors
--------------------------------------------------------------------------------

instance Functor (->) (->) ((,) e) where
  fmap f ~(a,b) = (a, f b)

instance Functor (->) (->) (Either e) where
  fmap _ (Left a) = Left a
  fmap f (Right b) = Right (f b)

instance Functor (->) (->) [] where
  fmap = Prelude.fmap

instance Functor (->) (->) Prelude.Maybe where
  fmap = Prelude.fmap

instance Functor (->) (->) Prelude.IO where
  fmap = Prelude.fmap

instance Functor (->) (Nat (->) (->)) (,) where
  fmap f = Nat (\(a,b) -> (f a, b))

instance Functor (->) (Nat (->) (->)) Either where
  fmap f0 = Nat (go f0) where
    go :: (a -> b) -> Either a c -> Either b c
    go f (Left a)  = Left (f a)
    go _ (Right b) = Right b

--------------------------------------------------------------------------------
-- * Type Equality
--------------------------------------------------------------------------------

instance Category (:~:) where
  id = Refl
  (.) = Prelude.flip Equality.trans

instance Functor (Y (:~:)) (Nat (:~:) (->)) (:~:) where
  fmap (Y f) = Nat (. f)

instance Functor (:~:) (->) ((:~:) e) where
  fmap = (.)

--------------------------------------------------------------------------------
-- * Type Coercions
--------------------------------------------------------------------------------

instance Category Coercion where
  id = Coercion
  (.) = Prelude.flip Coercion.trans

instance Functor (Y Coercion) (Nat Coercion (->)) Coercion where
  fmap (Y f) = Nat (. f)

instance Functor Coercion (->) (Coercion e) where
  fmap = (.)