data Company = Company [Dept] data Dept = Dept Name Manager [SubUnit] data SubUnit = EmpUnit Employee | DeptUnit Dept data Employee = Employee Person Salary data Person = Person Name Address data Salary = Salary Number type Manager = Employee type Name = String type Address = String MOTIVATION increase :: (Salary -> Salary) -> Company -> Company
class MapSalary a where increase ::(Salary -> Salary) -> a -> a instance mapSalary :: MapSalary Salary where increase f a = f a else instance mapSalary :: MapSalary a where increase _ a = a AD HOC OVERLOADING? Too much boilerplate. Need a general solution.
increase :: forall a. (Salary -> Salary) -> a -> a increase f a | a `instanceOf` Salary = f a | otherwise = a DESIRED SOLUTION instanceOf :: forall a. a -> Type?? -> Boolean
-Proxy a = Proxy -booleanType :: Proxy Boolean booleanType = Proxy -instanceOf :: forall a b. a -> Proxy b -> Boolean instanceOf a Proxy = ??? PROXY DOESN’T SUFFICE
-TypeRep a -typeRep :: forall a. TypeRep a -eqTypeRep :: forall a b. TypeRep a -> TypeRep b -> Boolean -instanceOf :: forall a. a -> TypeRep b -> Boolean instanceOf a t = eqTypeRep (typeRep :: _ a) t REIFY TYPES Predefined a == b => TypeRep a == TypeRep b
data TypeRep a where TInt :: Type Int TChar :: Type Char TArray :: Type a -> Type (Array a) TFunc :: Type b -> Type c -> Type (Function b c) TTuple :: Type a -> Type b -> Type (Tuple a b) eqTypeRep :: forall a b. TypeRep a -> TypeRep b -> Boolean eqTypeRep TInt TInt = True … MANUALLY - GADTS
data TypeRep a = TInt (Int ~ a) | TChar (Char ~ a) | TArray (Type b) (a ~ Array b) | TFunc (Type b) (Type c) (a ~ Function b c) | TTuple (Type b) (Type c) (a ~ (Tuple b c)) eqTypeRep :: forall a b. TypeRep a -> TypeRep b -> Boolean eqTypeRep (TInt w1) (TInt w2) = Just $ symm w1 >>> w2 … MANUALLY - WITHOUT GADTS Not extensible Explained later
increase :: forall a. (Salary -> Salary) -> a -> a increase f a | a `instanceOf` typeRep = f (coerceToSalary a) | otherwise = a coerceToSalary :: forall a. a -> Salary coerceToSalary = unsafeCoerce SOLUTION
increase :: forall a. (Salary -> Salary) -> a -> a increase f a = case a `instanceOf` typeRep of Just coercion = f (coercion a) Nothing -> a instanceOf :: forall a. a -> TypeRep b -> Maybe (a -> b) instanceOf ta tb | eqTypeRep ta tb = Just (unsafeCoerce identity) | otherwise = Nothing ENCAPSULATE UNSAFE BEHAVIOUR (TYPE WITNESSES)
increase :: forall a. (Salary -> Salary) -> a -> a increase f a = case cast a of Just n = f n Nothing -> a cast :: forall a b. Typeable a => Typeable b => a -> Maybe b cast a = case a `instanceOf` (typeRep :: _ b) of Nothing -> Nothing Just f -> f a EQUIVALENTLY Runtime cast
newtype Leibniz a b = Leibniz (forall f. f a -> f b) infix 4 type Leibniz as ~ runLeibniz :: forall f a b. a ~ b -> f a -> f b runLeibniz (Leibniz f) = f LEIBNIZ EQUALITY
eqT :: forall a b. TypeRep a -> TypeRep b -> Maybe (a ~ b) eqT ta tb | eqTypeRep ta tb = Just (unsafeCoerce (identity :: Leibniz a a)) | otherwise = Nothing cast :: forall a b. Typeable a => Typeable b => a -> Maybe b cast a = eqT (typeRep :: _ a) (typeRep :: _ b) :: Maybe (Identity a -> Identity b) # map \f -> runLeibniz f (Identity a) :: Maybe (Identity b) # map unwrap :: Maybe b CAST USING LEIBNIZ
class Typeable a => Data a where gmapT :: (forall b. Data b => b -> b) -> a -> a instance Data Employee where gmapT f (E per sal) = E (f per) (f sal) instance Data Bool where gmapT f x = x instance Data a => Data [a] where gmapT f [] = [] gmapT f (x:xs) = f x : f xs WRAPPING IT UP
everywhere :: Data a => (forall b. Data b => b -> b) -> a -> a everywhere f x = f (gmapT (everywhere f) x) solution :: (Salary->Salary) -> Company -> Company Solution k = everywhere (increase k) NO BOILERPLATE
data Dynamic' t a = Dynamic' (TypeRep a) (t a) data Dynamic t = Dynamic (Exists (Dynamic' t)) dynamic :: forall t a. Typeable a => t a -> Dynamic t dynamic a = Dynamic (mkExists (Dynamic' typeRep a)) unwrapDynamic :: forall t a. TypeRep a -> Dynamic t -> Maybe (t a) unwrapDynamic ta (Dynamic e) = e # runExists \(Dynamic' ti v) -> map (\w -> runLeibniz w v) (eqT ti ta) ANOTHER EXAMPLE - DYNAMIC VALUES
data Proxy0 (t :: Type) data Proxy1 (t :: Type -> Type) … foreign import proxy0 :: forall t. Proxy0 t foreign import proxy1 :: forall t. Proxy1 t … PROXY
class Tag0 a where tag0 :: Proxy0 a class Tag1 (a :: Type -> Type) where tag1 :: Proxy1 a … instance tagInt :: Tag0 Int where tag0 = proxy0 instance tagArray :: Tag1 Array where tag1 = proxy1 … TAGS User Defined Instances
instance tag1FromTag2 :: (Tag2 t, Typeable a) => Tag1 (t a) where tag1 = proxy1FromTag2 instance tag0FromTag1 :: (Tag1 t, Typeable a) => Tag0 (t a) where tag0 = proxy0FromTag1 … foreign import proxy1FromTag2 :: forall t a. Tag2 t => Typeable a => Proxy1 (t a) foreign import proxy0FromTag1 :: forall t a. Tag1 t => Typeable a => Proxy0 (t a) … TAG CHAINING A -> B -> [A,B] [A,B] -> C -> [A,B,C]
data TypeRow (r :: RL.RowList) foreign import typeRowToTypeRep :: RL.RowToList r rl => TypeRow rl -> TypeRep (Record r) foreign import typeRowNil :: TypeRow RL.Nil foreign import typeRowCons :: SProxy s -> TypeRep t -> TypeRow rs -> TypeRow (RL.Cons s t rs) TYPEABLE FOR ROW TYPES A -> A [] S -> T -> R -> (S,T):R