Skip to content
This repository has been archived by the owner on Jun 13, 2020. It is now read-only.

Latest commit

 

History

History
50 lines (35 loc) · 1.36 KB

a997bfa5.md

File metadata and controls

50 lines (35 loc) · 1.36 KB
title date
The `Has` pattern
2020-05-06

The Has pattern is used to access configuration or state in Layer 3 pure functions (see <fca6b335?cf>). 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