Skip to content

Support for capability-style records #19

@schell

Description

@schell

I really don't know if this is possible, but I'm referring to capability records like:

data LogCap (m :: Type -> Type) 
  = LogCap 
  { logInfo :: String -> String -> m ()
  , logError :: String -> String -> m () 
  } deriving Generic

From the outside these records look like HKDs - every field contains the type variable, but you might consider function parameters being "hidden" from it (one of the disclaimers from ProductB).

The first problem to solve is the FunctorB instance, as GFunctorB doesn't cut it:

• No instance for (barbies-1.1.3.0:Data.Barbie.Internal.Functor.GFunctorB
                         *
                         *
                         f
                         g
                         (Rec
                            *
                            (String
                             -> String
                             -> barbies-1.1.3.0:Data.Generics.GenericN.Param * * 0 f ())
                            (String -> String -> f ()))
                         (Rec
                            *
                            (String
                             -> String
                             -> barbies-1.1.3.0:Data.Generics.GenericN.Param * * 0 g ())
                            (String -> String -> g ())))

Intuitively though, it seems that we should be able to traverse an arrow with (f a -> g a), drilling deeper by creating lambdas until we come to an m a.

The point of all this is that at the end of the day it would be nice to be able to write a generic lift function for any of these forms of HKDT.

Given:

newtype Apply (f :: Type -> Type) (g :: Type -> Type) a
  = Apply { runApply :: f a -> g a }


bapply
  :: ProductB b
  => b (Apply i o)
  -> b i
  -> b o
bapply =
  bzipWith runApply

You could easily do something like:

let 
  ioLogCap :: LogCap IO 
  ioLogCap = ioLoggingCapabilities 

  resourceTLogCap :: LogCap (ResourceT IO) 
  resourceTLogCap = bapply (buniq $ Apply lift) ioLogCap
in 
  runResourceT $ f resourceTLogCap

which could kill a pleasant amount of boilerplate when using capability records.

Thoughts? I might be crazy ¯_(ツ)_/¯

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions