2016-07-21 41 views
6

Ich versuche Monade transfromers von scalaz in Haskell Art und Weise zu stapeln:Stacking Monade Transformatoren in scala

statyReader :: (MonadReader Int m, MonadState Int m) => m Int 

scala:

def statyReader[F[_]](implicit r: MonadReader[F, Int], s: MonadState[F, Int]): F[Int] = for { 
    counter <- s.get 
    secret <- r.ask 
    _  <- s.put(counter + secret) 
    } yield counter 

Es kompiliert mit 1 implizit vergangen, aber nicht mit 2 :

Error:(13, 18) value flatMap is not a member of type parameter F[Int] 
    counter <- s.get 
       ^
Error:(14, 18) value flatMap is not a member of type parameter F[Int] 
    secret <- r.ask 
       ^
Error:(15, 21) value map is not a member of type parameter F[Unit] 
    _  <- s.put(counter + secret) 
        ^

Warum passiert das? Meine Vermutung ist, dass Compiler jetzt verwirrt ist, die "monadische Instanz von F[_]" sollte wählen (beide MonadReader und MonadState erweitern Monad[F[_]). Ist das eine richtige Schätzung?

Wie überwinde ich das?

+4

Minor Punkt: In Haskell, würde ich nicht Nennen Sie das "Stacking Monad Transformers", da ich damit zB auf 'StateT s (LeserT r IO) a '. Es ist jedoch richtig, dass wir in einem solchen Stapel mehrere Typenbeschränkungen haben, also ist es verwandt. – chi

+0

Ich glaube nicht, dass die zwei impliziten Parameter das Problem sind, sonst würden Sie den Fehler "mehrdeutige implizite Werte" erhalten (siehe https://github.com/scalaz/scalaz/issues/1110). – devkat

+0

@devkat wenn ich nur 1 implizit übergebe, funktioniert die Sache :) –

Antwort

1

Das ist nicht wirklich eine Antwort, aber hilft vielleicht ein bisschen.

Ich denke, du hast recht; Es sieht so aus, als ob der Compiler die F[_] Typen beider Parameter (ich nehme an, es handelt sich um einen höheren Typ mit mehreren möglichen Instanzen und nicht um eine konkrete Instanz) nicht zu einem Monad-Typ vereinheitlichen kann. Die Kompilierung arbeitet mit separaten Parameterlisten, da die Typisierung nur innerhalb einer Parameterliste erfolgt. Es kann weiter wie folgt erläutert werden:

def statyReader[F[_]](implicit r: MonadReader[F, Int], s: MonadState[F, Int]): F[Int] = 
    statyReader2(r, s) 

def statyReader2[F[_]:Monad](r: MonadReader[F, Int], s: MonadState[F, Int]): F[Int] = 
    for { 
    counter <- s.get 
    secret <- r.ask 
    _ <- s.put(counter + secret) 
    } yield counter 

Error: ambiguous implicit values: both 
value s of type scalaz.MonadState[F,Int] and 
value r of type scalaz.MonadReader[F,Int] 
match expected type scalaz.Monad[F] 

Offensichtlich als eine Abhilfe Sie zwei Parameterlisten verwenden könnte zu wählen, welche Monade Sie verwenden möchten:

def statyReader[F[_]](implicit r: MonadReader[F, Int], s: MonadState[F, Int]): F[Int] = 
    statyReader2(r)(s) 

def statyReader2[F[_]](r: MonadReader[F, Int])(implicit s: MonadState[F, Int]): F[Int] = 
    for { 
    counter <- s.get 
    secret <- r.ask 
    _ <- s.put(counter + secret) 
    } yield counter