2011-12-03 12 views
5

Używam operational monad przez Heinricha Apfelmusa. Chciałbym sparametryzować interpreter z monadą dla typu wyniku. Poniższa wersja mojego kodu kompiluje:Monada operacyjna z tłumaczem w dowolnej monadzie

{-# LANGUAGE GADTs #-} 

import Control.Monad.Operational 

data EloI a where 
    Display :: Int -> EloI() 

type Elo a = Program EloI a 

interpret :: Monad m => (Int -> m()) 
        -> Elo a 
        -> Int 
        -> m a 
interpret display = interp 
    where 
    interp :: Monad m => Elo a -> Int -> m a 
    interp = eval . view 
    eval :: Monad m => ProgramView EloI a -> Int -> m a 
    eval (Display i :>>= is) s = interp (is()) s 

Teraz zmienić ostatni wiersz do

eval (Display i :>>= is) s = display i >> interp (is()) s 

i typu wnioskowania nie uda już, mam wyjście

nie mógł dedukuj (m ~ m1) z kontekstu (Monad m)
związany podpisem typu do interpretacji :: Monad m => (Int -> m()) -> Elo a -> Int -> ma (.. .)

Po usunięciu podpisu typu dla interp, otrzymuję dodatkowy błąd (nie mógł wydedukować (a1 ~ a)).
Kiedy zmieniam wszystkie m na IO (jak w przypadku tic tac toe dla monady operacyjnej), to kompiluje się ponownie.
Czy próbuję czegoś, co nie ma sensu, czy mogę podać wskazówkę do GHC? Muszę przyznać, że nie jestem pewien, czy potrzebuję tej elastyczności.

Odpowiedz

8

To dlatego, że m w sygnaturach typu lokalnego są zmiennymi świeżego typu, więc obiecują pracować z dowolną monadą. Jeśli używasz display, eval może działać tylko dla określonych zastosowań monady display. To powinno działać, jeśli a) usunąć lokalne podpisy typu, lub b) wprowadzają typ zmiennej m w zakresie

{-# LANGUAGE ScopedTypeVariables #-} 
... 
interpret :: forall m. (Int -> m()) -> Elo a -> Int -> m a 
+0

nawet nie próbować a) (althaugh I zazwyczaj nie korzystają z podpisami typu lokalnych), ponieważ poniższej instrukcji w przykładowym kodzie "Należy pamiętać, że ponieważ ProgramView jest GADT, adnotacja typu dla eval jest obowiązkowa." – Duschvorhang