2016-12-29 3 views
0

私はFreeMonadsを使用して私のサービスのためのインタプリタを実装する方法を学ぼうとしています。アクションをチェーン化してScalazと一緒に解釈するにはどうすればいいですか?

私は

sealed trait ServiceAction[T] extends Product with Serializable 
case class ConsumeCommand(cmd: AccruePoints) extends ServiceAction[AccruePointModel] 
case class CreateEvent(evt: PointsAccruedEvent) extends ServiceAction[PointsAccruedEvent] 

sealed trait LogAction[T] extends Product with Serializable 
case class Info(msg: String) extends LogAction[Unit] 
case class Error(msg: String) extends LogAction[Unit] 

とアクション

type LogActionF[A] = Free[LogAction, A] 
type ServiceActionF[A] = Free[ServiceAction, A] 

次のモナドがあると、私はこのように私のサービスを定義します。

trait PointAccrualService { 
    def consume(cmd: AccruePoints): ServiceActionF[AccruePointModel] = Free.liftF(ConsumeCommand(cmd)) 
    def emit(evt: PointsAccruedEvent) : ServiceActionF[PointsAccruedEvent] = Free.liftF(CreateEvent(evt)) 
} 

trait LogService { 
    def info(msg: String) : LogActionF[Unit] = Free.liftF(Info(msg)) 
    def error(msg: String) : LogActionF[Unit] = Free.liftF(Error(msg)) 
} 

object LogService extends LogService 
object PointAccrualService extends PointAccrualService 

の対象と

マイLogServiceInterpreterはこのようなものです:

case class LogServiceConsoleInterpreter() extends LogServiceInterpreter { 
    def apply[A](action: LogActionF[A]): Task[A] = action.foldMap(handler)    

    protected def handler = new (LogAction ~> Task) { 
    override def apply[A](fa: LogAction[A]) = fa match { 
     case Info(m) => 
     now(info(m)) 
     case Error(m) => 
     now(error(m)) 
    } 
    } 

    def info(msg: String): Unit = { 
    println(s"INFO: $msg") 
    } 

    def error(msg: String): Unit = { 
    println(s"ERROR: $msg") 
    } 
} 

同様に、私のPointAccuralServiceInterpreterはこのようなものです:

case class PointAccuralServiceInterpreter() { 
    def apply[A] (action: ServiceActionF[A]) : Task[A] = action.foldMap(handler) 
    protected def handler = new (ServiceAction ~> Task) { 
    override def apply[A](fa: ServiceAction[A]): Task[A] = fa match { 
     case ConsumeCommand(cmd) => { 
     println("Service ConsumeCommand:" + cmd) 
     now(cmd) 
     } 
     case CreateEvent(evt) => { 
     println("Service CreateEvent:" + evt) 
     now(evt) 
     } 
    } 
    } 
} 

私のロジックは、私が欲しい、簡単ですログに記録し、私のコマンドを消費して、イベントを作成する、ソーシングのようなイベントのようなもの:

val ret = for { 
    _ <- logService.info("Command: " + cmd) 
    model <- service.consume(cmd) 
    _ <- logService.info("Model: " + model) 
    evt <- service.emit(model.toEvent("200", "Event Sent")) 
    _ <- logService.info("Event:" + evt) 
} yield evt 

このコードは実際にはコンパイルされません。

ここから何をすればよいですか?私はCoproductを使ってそれらを連鎖させ、私の通訳に給油することによってこの論理を実行することになっていると思います。

私はここ https://groups.google.com/forum/#!topic/scalaz/sHxFsFpE86c

何かを見つけたり、私がそう Folding a list of different types using Shapeless in Scala

彼らはあまりにも複雑でやって型崩れを使用することができると述べています。私が望むのは、自分のロジックを定義した後、どのように実行すればよいのでしょうか?

私は答えのために十分な詳細をここに入れています。私は本当にこれを学びたい。ありがとう

+2

:ここ

は完全なコードです。 – pedrofurla

+0

申し訳ありませんが、コードを追加しましょう。私は他の人と一緒に昼食のために急いだ。私は体にもっと入れておくべきだった – sowen

答えて

1

自己実行型の例を作成するためにコードを少し修正しました。私はScalaz 7.2を使用してRúnar Bjarnason's ideasに従って、あなたのプログラムをどのように実行するか、あなたの質問に可能な答えを加えました。 (私はScalazで自然変換のためのorオペレータを見つけられませんでしたので、私はここにこれを追加しました。)

を私はまた、あなたの行動を与えることをいじるために何かをいくつかのスタブを追加して以来、(内部ハンドラにあなたのサービスを簡素化私は両方の言語を組み合わせて新しいサービスを作成しなければならなかった)。さらに、Task.now{...}Task{...}に変更して非同期タスクを作成しました。このタスクはコードの最後の行で実行されます。あなたの質問は全く明らかではない

import scala.language.{higherKinds, implicitConversions} 

import scalaz._ 
import scalaz.concurrent.Task 

/* Stubs */ 

case class AccruePoints() 
case class AccruePointModel(cmd: AccruePoints) { 
    def toEvent(code: String, description: String): PointsAccruedEvent = PointsAccruedEvent(code, description) 
} 
case class PointsAccruedEvent(code: String, description: String) 

/* Actions */ 

sealed trait ServiceAction[T] extends Product with Serializable 

case class ConsumeCommand(cmd: AccruePoints) extends ServiceAction[AccruePointModel] 
case class CreateEvent(evt: PointsAccruedEvent) extends ServiceAction[PointsAccruedEvent] 

sealed trait LogAction[T] extends Product with Serializable 

case class Info(msg: String) extends LogAction[Unit] 
case class Error(msg: String) extends LogAction[Unit] 

/* Handlers */ 

object PointAccuralServiceHandler extends (ServiceAction ~> Task) { 
    override def apply[A](fa: ServiceAction[A]): Task[A] = fa match { 
    case ConsumeCommand(cmd) => { 
     println("Service ConsumeCommand:" + cmd) 
     Task(consume(cmd)) 
    } 
    case CreateEvent(evt) => { 
     println("Service CreateEvent:" + evt) 
     Task(evt) 
    } 
    } 

    def consume(cmd: AccruePoints): AccruePointModel = 
    AccruePointModel(cmd) 
} 

case object LogServiceConsoleHandler extends (LogAction ~> Task) { 
    override def apply[A](fa: LogAction[A]): Task[A] = fa match { 
    case Info(m) => 
     Task(info(m)) 
    case Error(m) => 
     Task(error(m)) 
    } 

    def info(msg: String): Unit = { 
    println(s"INFO: $msg") 
    } 

    def error(msg: String): Unit = { 
    println(s"ERROR: $msg") 
    } 
} 

/* Execution */ 

class Service[F[_]](implicit I1: Inject[ServiceAction, F], I2: Inject[LogAction, F]) { 
    def consume(cmd: AccruePoints): Free[F, AccruePointModel] = Free.liftF(I1(ConsumeCommand(cmd))) 

    def emit(evt: PointsAccruedEvent): Free[F, PointsAccruedEvent] = Free.liftF(I1(CreateEvent(evt))) 

    def info(msg: String): Free[F, Unit] = Free.liftF(I2(Info(msg))) 

    def error(msg: String): Free[F, Unit] = Free.liftF(I2(Error(msg))) 
} 

object Service { 
    implicit def instance[F[_]](implicit I1: Inject[ServiceAction, F], I2: Inject[LogAction, F]) = new Service[F] 
} 

def prg[F[_]](implicit service: Service[F]) = { 
    val cmd = AccruePoints() 
    for { 
    _ <- service.info("Command: " + cmd) 
    model <- service.consume(cmd) 
    _ <- service.info("Model: " + model) 
    evt <- service.emit(model.toEvent("200", "Event Sent")) 
    _ <- service.info("Event:" + evt) 
    } yield evt 
} 

type App[A] = Coproduct[ServiceAction, LogAction, A] 

def or[F[_], G[_], H[_]](f: F ~> H, g: G ~> H) = 
    new (({type t[x] = Coproduct[F, G, x]})#t ~> H) { 
    override def apply[A](c: Coproduct[F, G, A]): H[A] = c.run match { 
     case -\/(fa) => f(fa) 
     case \/-(ga) => g(ga) 
    } 
    } 

val app = prg[App] 

val ret = app.foldMap(or(PointAccuralServiceHandler, LogServiceConsoleHandler)) 
ret.unsafePerformSync 
関連する問題