2016-06-28 3 views
2

Je travaille à travers la définition de Prompt et son Bind instance décrit here et essayait de comprendre comment cela ressemblerait dans Purescript. J'utilise Purescript.Exists pour le type existentiel. Mon défintion est alors:Invite Monad dans Purescript

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

Je suis coincé sur l'écriture du en particulier, le cas Ask dans le cas Bind et je suis très confus au sujet des types lorsque vous travaillez avec runExists.

Comment écrire cette instance?

Merci,

Michael

Répondre

1

Quelque chose comme ça devrait faire l'affaire:

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) 

La fonction mapPA est une commodité pour la mise à jour la poursuite PromptAskF sans avoir à plusieurs reprises runExists/mkExists.

+0

Bonjour Gary, merci de votre réponse. Cela a du sens pour moi mais pas, apparemment, pour le vérificateur de type! J'obtiens l'erreur suivante: 'Erreur trouvée: dans le module principal à la ligne 26, colonne 1 - ligne 30, colonne 26 Une variable de type a échappé à sa portée. dans l'expression (flip runExists) demande dans la déclaration de valeur bindPrompt' –

+0

Je viens de mettre à jour la réponse pour inclure l'implémentation complète afin de s'assurer qu'elle soit réellement typechecks cette fois! Ce message d'erreur peut être assez difficile à traiter parfois, dans ce cas, il était dû à 'flip'ping' runExists', mais même après cela il y avait un peu d'étrangeté (ne pouvait pas mettre le lambda dans un 'where' sans qu'il en résulte). Le déplacer vers 'runPA' le rend un peu plus facile à lire, et fournir la signature de type explicite pour la fonction de mappage permet d'éviter d'autres problèmes potentiels d'échappement de skolem. –

+0

Génial! Merci d'avoir pris le temps de mettre à jour. C'est plus clair pour moi que l'implémentation de Haskell, grâce aux types rank-n explicites. –