AgentLiquid
AgentLiquid

Reputation: 3682

Creating a wrapper Monad around IO

Suppose I want to create a wrapping Monad that takes an IO Action and wraps it as follows. The sequence operator (>>) works just fine, but I'm having a hard time implementing return and >>=.

I tried return x = DelayedAction (return x) but that doesn't result in the correct type.

newtype DelayedAction a = DelayedAction {action :: IO a}

instance Functor DelayedAction where
  fmap = liftM

instance Applicative DelayedAction where
  pure = return
  (<*>) = ap

instance Monad DelayedAction where
  return x = undefined
  (DelayedAction firstIO) >>= f = undefined

  (DelayedAction firstIO) >> (DelayedAction secondIO) =
    DelayedAction
      ( do
          firstIO
          threadDelay 1000000
          secondIO
      )

Upvotes: 2

Views: 201

Answers (1)

AgentLiquid
AgentLiquid

Reputation: 3682

@Aplet123 and @leftaroundabout clarified that this can't be a real monad since it can't follow Monad laws. Nonetheless, I was able to come up with a solution that made the compiler happy. Taught me a lot about monads, type-classes, types, do-notation, etc.

instance Monad DelayedAction where
  return x = DelayedAction (return x)

  da >>= f =
    DelayedAction
      ( do
          firstIOValue <- action da
          threadDelay 1000000
          (action . f) firstIOValue
      )

De-sugared version of bind:

da >>= f =
  DelayedAction
    ( action da >>= (\firstIOValue -> threadDelay 1000000 >> (action . f) firstIOValue)    

Upvotes: 1

Related Questions