module Conduit.App.Has where -- | Enables more semantic typing & allows for stronger free theorems. sm0rt. See 'grab'. -- Unfortunately can't do the following without enabling ImpredicativeTypes which I -- believe isn't entirely supported, but I may be wrong there. Lmk! -- -- > type Has f m = (∀ c. MonadReader c m, ∀ c. Has' f c) :: Constraint type Has f c m = (MonadReader c m, Has' f c) -- | row polymorphism my beloved class Has' field container where obtain :: container -> field -- | Works with 'Has' -- -- > newtype Name = Name Text deriving (Show) -- > newtype NameBox = NameBox { nm :: Name } -- > -- > instance Has' Name NameBox where -- > obtain :: NameBox -> Name -- > obtain = nm -- > -- > test :: (Has Name c m, MonadIO m) -> m () -- > test = do -- > name <- grab @Name -- > print name -- > -- > main :: IO () -- > main = runReaderT test (NameBox $ Name "hi") grab :: ∀ field container m. (Has field container m) => m field grab :: forall field container (m :: * -> *). Has field container m => m field grab = (container -> field) -> m field forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a asks ((container -> field) -> m field) -> (container -> field) -> m field forall a b. (a -> b) -> a -> b $ forall field container. Has' field container => container -> field obtain @field {-# INLINE grab #-}