{-# LANGUAGE Safe #-} {-# LANGUAGE MultiParamTypeClasses, ConstraintKinds, TypeOperators, FlexibleInstances #-} --{-# LANGUAGE UndecidableInstances, AllowAmbiguousTypes #-} {-| Module : Text.Gigaparsec.Expr.Subtype Description : This module defines explicit subtyping, with up- and -downcasting. License : BSD-3-Clause Maintainer : Jamie Willis, Gigaparsec Maintainers Stability : experimental This module defines explicit subtyping, with up- and -downcasting. Subtyping is used in "Text.Gigaparsec.Expr" to allow for more specific types within a single layer of a precedence table, as long as they all have a common supertype. -} module Text.Gigaparsec.Expr.Subtype ( -- ** Subtyping {-| -} Subtype(upcast, downcast), type (<), -- ** Module Re-export -- | This should be removed. module Text.Gigaparsec.Expr.Subtype) where import Data.Kind (Constraint) --import Control.Monad ((>=>)) {-| Explicit subtyping with up- and down-casting. @sub@ is a 'Subtype' of @sup@ when there is an /upcasting/ function @sub -> sup@. The intuition is that for each value of type @sub@, there is a (unique) corresponding value in @sup@ `upcast` will convert values in @sub@ to their corresponding values in @sup@. The `downcast` function describes all those values in @sup@ which correspond to values in @sub@; if @v :: sup@ does not correspond to any value in @sub@, then @'downcast' v = 'Nothing'@. This is encapsulated by the following property: prop> downcast . upcast = Just meaning that `upcast` should be a right inverse for `downcast`. In other words, if you `upcast` and then `downcast` some value, you will end up with the same value (albeit wrapped under a 'Just'). -} type Subtype :: * -> * -> Constraint class Subtype sub sup where {-| Inject the subtype into the supertype. Cast values in @sub@ into a value of type @sup@. This should be a right inverse of 'downcast'. -} upcast :: sub -> sup {-| Describes which elements of @sup@ correspond with those in @sub@. That is, @'downcast' v = 'Just' w@ precisely when @'upcast' w = v@. If @v :: sup@ corresponds with some element @w :: sub@, then, > downcast v = Just w Otherwise, if @v :: sup@ is not the upcast of any element of @sub@, then, > downcast v = Nothing -} downcast :: sup -> Maybe sub {-| An infix alias of 'Subtype'. -} type (<) :: * -> * -> Constraint type sub < sup = Subtype sub sup instance Subtype a a where upcast :: a -> a upcast = a -> a forall a. a -> a id downcast :: a -> Maybe a downcast = a -> Maybe a forall a. a -> Maybe a Just -- This instance is just evil {-instance forall b a c. (a < b, b < c) => Subtype a c where upcast = upcast @b @c . upcast @a @b downcast = downcast @b @c >=> downcast @a @b -}