Michael Thomas
Michael Thomas

Reputation: 1354

Prompt Monad in Purescript

I'm working through the definition of Prompt and its Bind instance described here and was trying to figure out how this would look in Purescript.

I am using Purescript.Exists for the existential type. My defintion is then:

data PromptAskF p r a
  = PromptAskF (p a) (a -> Prompt p r)

type PromptAsk p r = Exists (PromptAskF p r)

data Prompt p r
  = Ask (PromptAsk p r)
  | Answer r 

instance bindPrompt :: Bind (Prompt p) where
  bind (Answer x) k = k x
  bind (Ask ask) k = ???

I am stuck on writing the Ask case in the Bind instance and, in particular, I'm very confused about the types when working with runExists.

How should I write this instance?

Thanks,

Michael

Upvotes: 2

Views: 205

Answers (1)

gb.
gb.

Reputation: 4649

Something like this should do the trick:

data PromptAskF p r a
  = PromptAskF (p a) (a -> Prompt p r)

type PromptAsk p r = Exists (PromptAskF p r)

mapPA
  :: forall p r r'
   . (forall a. (a -> Prompt p r) -> (a -> Prompt p r'))
  -> PromptAsk p r
  -> PromptAsk p r'
mapPA f = runExists \(PromptAskF req cont) -> mkExists $ PromptAskF req (f cont)

data Prompt p r
  = Ask (PromptAsk p r)
  | Answer r

instance functorPrompt :: Functor (Prompt p) where
  map f (Answer r) = Answer (f r)
  map f (Ask ask) = Ask $ mapPA (map (map f)) ask

instance applyPrompt :: Apply (Prompt p) where
  apply = ap

instance applicativePrompt :: Applicative (Prompt p) where
  pure = Answer

instance bindPrompt :: Bind (Prompt p) where
  bind (Answer x) k = k x
  bind (Ask ask) k = Ask $ mapPA (\cont ans -> cont ans >>= k) ask

instance monadPrompt :: Monad (Prompt p)

The mapPA function is a convenience for updating the PromptAskF continuation without having to repeatedly runExists / mkExists.

Upvotes: 1

Related Questions