The Has pattern

The Has pattern is used to access configuration or state in Layer 3 pure functions (see Three Layer Haskell Cake). The class itself is defined like this in the three-layer app:

class Has field env where
  obtain :: env -> field

instance Has a a where
  obtain = id

grab :: forall field env m. (MonadReader env m, Has field env) => m field
grab = asks $ obtain @field

Layer 3 use

Begin by creating an constraint alias. We will use MonadReader as it is the most convenient, and also used by the utility grab function defined above. This particular example is for passing database connections around:

type WithDb env m = (MonadReader env m, Has Connection env, MonadIO m)

-- An helper to work with the constraint
withDb :: WithDb env m => (Connection -> IO b) -> m b
withDb f = do
  conn <- grab @Connection
  liftIO $ f conn

Then any application-level function which queries on the database would use it as:

getUsers :: WithDb env m => m [User]
getUsers = undefined

Layer 1 use

To tie them all together, you would use runReaderT from the suitable top-level function:

users <- flip runReaderT conn getUsers

See also