Chris Grounds (formerly Chris Bacon)

Portfolio

Twitter Github
4 March 2019

Haskell Through Example: ReaderT

by Christopher Bacon

Twitter bot serverless function

Scenario: Suppose we have a config object for which we only want to pull off certain values.

import Control.Monad.Trans.Reader

data Config = Config
  { functionName       :: String
  , functionTimeout    :: Int
  , functionPermission :: Role
  , functionMemorySize :: Int
  }
  
data Role = Admin | User

mkQuery :: Monad m => ReaderT Config m [Int]
mkQuery = do
  timeout    <- asks functionTimeout
  memorySize <- asks functionMemorySize
  return [timeout, memorySize]

main :: IO ()
main = do
  let config = Config "twitter-bot-function" 360 Admin 100

  queryResult <- runReaderT myQuery config

  print queryResult

Which will print out

[360, 10]

Hierarchy of function calls

Scenario: Suppose we have an embedded hierarchy of function calls, and we want to pull out some configuration value at the botton of this function call stack.

import Control.Monad.Trans.Reader

data Config = Config { password :: String }

top :: Monad m => ReaderT Config m String
top = middle

middle :: Monad m => ReaderT Config m String
middle = bottom

bottom :: Monad m => ReaderT Config m String
bottom = asks password

main :: IO ()
main = do
  let c = Config "password1234"
  res <- runReaderT top c
  print res

Which will print out

password1234

Environment with nested values

Scenario: Suppose we have a environment with nested values, and we want to pull off certain values.

module Main where

import Control.Monad.Trans.Reader

data Env = MkEnv 
  { rootPassword :: Text
  , user         :: User 
  } deriving (Eq, Show)

data User = User 
  { name     :: Text
  , address  :: Text
  } deriving (Eq, Show)

myQuery :: Monad m => ReaderT Env m [Text]
myQuery = do
  rootPword   <- asks rootPassword
  userName    <- asks $ name . user
  userAddress <- asks $ address . user

  return [rootPword, userName, userAddress]

main :: IO ()
main = do
  let c = MkEnv "password" (User "Pompeii" "Rome")

  query <- runReaderT myQuery c

  print query

Which will print out

["password", "Pompeii", "Rome"]
tags: