2016-06-28 65 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類型。 –