2016-06-28 25 views
2

我正在通过Prompt及其Bind实例中描述的here的定义工作,并试图弄清楚Purescript会如何显示。Purescript中的提示Monad

我正在使用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 = ??? 

我被困在了Bind实例编写Ask情况下,特别是,我runExists工作时很担心的类型非常困惑。

我该如何写这个实例?

感谢,

迈克尔

回答

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便利。

+0

嗨加里,谢谢你的回答。这对我来说很有意义,但对于类型检查者来说显然不是。我收到以下错误:'发现错误: 模块Main 在26行,第1行 - 第30行,第26列 一个类型变量已经转移了它的范围。 在表达式(flip runExists)中询问 的值声明bindPrompt' –

+0

我刚刚更新了答案,以包含完整实现以确保它实际上是类型检查!这个错误信息有时可能很难处理,在这种情况下,这是由于'runExists'翻转了,但即使在这之后仍然存在一些怪异现象(无法将lambda放入“where”中)。将它移动到'runPA'使其更容易阅读,并为映射函数提供显式类型签名有助于避免其他潜在的skolem转义问题。 –

+0

太棒了!感谢您花时间更新。这实际上比Haskell实现更清晰,这要归功于明确的rank-n类型。 –