Skip to content

solomon-b/graded-monads

Repository files navigation

Graded Monads

🚨 WORK IN PROGRESS 🚨

graded-monads::CI

A Graded Monad 𝐺 maps from a Monoidal Category (𝔼, ⊗, Iₑ) to the Category of Endofunctors: 𝐺 : 𝔼 → [ℂ, ℂ].

Graded Monads give you two monad-like operations:

η : Id → G Iₑ
μ : 𝐺 x ∘ 𝐺 y → 𝐺 (x ⊗ y)

Which capture, or 'grades', the monad with objects of 𝔼.

This library encodes graded monads in Haskell for managing effects using a QualifiedDo interface:

type GradedMonad ::
  ([Type] -> Type -> Type) ->
  Type ->
  (Type -> Type -> Type) ->
  Constraint
class (FunctorF m) => GradedMonad m i t | m -> i t where
  {-# MINIMAL greturn, (gjoin | gbind) #-}
  greturn :: Identity ~> m '[]

  gjoin :: (AppendTensored xs) => (m xs `Compose` m ys) ~> m (xs ++ ys)
  gjoin (Compose m) = m `gbind` id

  gbind :: (AppendTensored xs) => m xs a -> (a -> m ys b) -> m (xs ++ ys) b
  gbind mxa f = gjoin $ Compose $ fmap f mxa

We currently have graded version of ExceptT and WriterT.

The graded form of ExceptT allows you to track specify specific error types per subroutine and tensor those error types together when performaing a graded bind:

mkRequest :: (GradedMonadError m) => String -> m '[ParseError] Request
mkRequest _ = G.return Request

transformRequest :: (GradedMonadError m) => Request -> m '[TransformError] Request
transformRequest _ = gthrowError TransformError


invokeRequest _ = G.return Response

main :: IO ()
main = do
  result <- runExceptT' $ G.do
    req <- mkRequest "hoogle.hackage.com"
    req' <- transformRequest req
    invokeRequest req'

  case result of
   Left (Left ParseError) -> print ParseError
   Left (Right (Left TransformError)) -> print TransformError
   Left (Right (Right HttpError)) -> print HttpError
   Right Response -> print Response

The graded form of WriterT allows you to specifiy unique log types per subroutine in a similar manner:

mkRequest :: (GradedMonadWriter m) => String -> m '[ParseLog] Request
mkRequest _ = G.do
  gtell ParseLog
  G.return Request

transformRequest :: (GradedMonadWriter m) => Request -> m '[TransformLog] Request
transformRequest _ = G.do
  gtell TransformLog
  G.return Request

invokeRequest :: (GradedMonadWriter m) => Request -> m '[HttpLog] Response
invokeRequest _ = G.do
  gtell HttpLog
  G.return Response

main :: IO ()
main = do
  result <- runWriterT' $ G.do
    req <- mkRequest "hoogle.hackage.com"
    req' <- transformRequest req
    invokeRequest req'

  -- result :: (Response, Tensored (,) () '[ParseLog, TransformLog, HttpLog])
  print result

About

Graded Monads with a QualifiedDo interface

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published