在Purescript中提示Monad

时间:2016-06-28 14:00:13

标签: monads existential-type purescript

我正在研究Prompt及其Bind实例所定义的here的定义,并试图弄清楚Purescript的效果如何。

我使用Purescript.Exists作为存在类型。我的定义是:

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 = ???

我坚持在Ask实例中编写Bind案例,特别是在使用runExists时,我对这些类型感到非常困惑。

我该怎么写这个实例?

谢谢,

迈克尔

1 个答案:

答案 0 :(得分:1)

这样的事情可以解决问题:

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)

mapPA功能可以方便地更新PromptAskF延续,而无需重复runExists / mkExists