Created
May 1, 2017 03:49
-
-
Save kenbot/dbe3cbab959b2c1e09c16f34328e3a6b to your computer and use it in GitHub Desktop.
Example of Coyoneda use with free monads in Scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import scalaz._, Scalaz._ | |
// Model | |
case class UserId(id: String) | |
case class RequestId(id: String) | |
case class Message(body: String) | |
trait Authenticator { def authenticate(token: String): Option[UserId] } | |
trait MessageDb { | |
def getMessageList(id: String): List[String] | |
def addMessage(id: String, body: String): Unit | |
} | |
// DSL instructions | |
sealed trait AppAction[A] | |
case class Authenticate(token: String) extends AppAction[Option[UserId]] | |
case object GetRequestId extends AppAction[RequestId] | |
case class GetMessages(uid: UserId) extends AppAction[Seq[Message]] | |
case class AddMessage(uid: UserId, msg: Message) extends AppAction[Unit] | |
// User-facing monadic interface | |
object Scripts { | |
type ScriptImpl[A] = Coyoneda[AppAction, A] | |
type Script[A] = Free[ScriptImpl, A] | |
def authenticate(token: String): Script[Option[UserId]] = toScript(Authenticate(token)) | |
def getRequestId: Script[RequestId] = toScript(GetRequestId) | |
def getMessages(uid: UserId): Script[Seq[Message]] = toScript(GetMessages(uid)) | |
def addMessage(uid: UserId, msg: Message): Script[Unit] = toScript(AddMessage(uid, msg)) | |
private def toScript[A](a: AppAction[A]): Script[A] = Free.liftFC[AppAction, A](a) | |
type Interpreter[F[_]] = AppAction ~> F | |
def interpret[A, F[_]: Monad](script: Script[A], interp: Interpreter[F]): F[A] = Free.runFC(script)(interp) | |
} | |
// Interpreter | |
class AppInterpreter(auth: Authenticator, rid: RequestId, db: MessageDb) extends Scripts.Interpreter[Id] { | |
def apply[A](action: AppAction[A]): A = action match { | |
case Authenticate(token) => auth.authenticate(token) | |
case GetRequestId => rid | |
case GetMessages(UserId(id)) => db.getMessageList(id).map(Message.apply) | |
case AddMessage(UserId(id), Message(body)) => db.addMessage(id, body) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment