Skip to content

Instantly share code, notes, and snippets.

@paulvictor
Last active January 24, 2019 08:01
Show Gist options
  • Select an option

  • Save paulvictor/3f1eb63c87741096b3ba6ed95f2d6142 to your computer and use it in GitHub Desktop.

Select an option

Save paulvictor/3f1eb63c87741096b3ba6ed95f2d6142 to your computer and use it in GitHub Desktop.
Nesting of Monads
exports.fetchPayload = null
exports.readHostNameFromSTDIN = null;
module TransformersExample where
import Prelude
import Control.Monad.Except.Trans (ExceptT(..))
import Control.Monad.State.Class (get)
import Control.Monad.State.Trans (StateT(..), evalStateT, put)
import Control.Monad.Trans.Class (lift)
import Data.Either (Either)
import Data.Newtype (wrap)
import Data.Traversable (for)
import Data.Tuple.Nested (type (/\), (/\))
import Effect.Aff (Aff)
import Effect.Aff.Class (liftAff)
import Effect.Exception (Error)
type URL = String
type Payload = String
type Response = { code:: Int, payload :: Payload }
type Count = Int
type HostName = String
type URLPath = String
type QueryString = String
foreign import fetchPayload :: URL -> Aff (Either Error Response)
foreign import readHostNameFromSTDIN :: Aff HostName
-- Here ExceptT is the inner Monad and the StateT is the outer monad with the state being carried through being the current URL and the total redirects count.
-- State can be updated even with an error
example1 :: StateT (URL /\ Count) (ExceptT Error Aff) _
example1 = do
(url /\ count ) <- get
{ code, payload } <- lift $ wrap (fetchPayload url)
-- Here let's say that `fetchPayload` gave a Error ( a Left value), the chain of computations would stop.
-- So let's say, here that I want to reset `count` to 0 and retry from the last known URL, we can't
-- This is because of https://github.com/purescript/purescript-transformers/blob/v4.1.0/src/Control/Monad/State/Trans.purs#L97
if code == 301 && count < 5 then put (payload /\ (count + 1)) *> example1 else pure payload
example2 :: ExceptT Error (StateT (URLPath /\ QueryString) Aff) _
example2 = do
finalURL <- lift $ do
hostname <- liftAff readHostNameFromSTDIN
(urlPath /\ qs) <- get
pure $ "https://" <> hostname <> urlPath <> qs
liftAff $ fetchPayload finalURL
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment