Skip to content

Instantly share code, notes, and snippets.

@orionll
Last active August 29, 2015 14:16
Show Gist options
  • Select an option

  • Save orionll/a5db66b5eeb6379d1e1a to your computer and use it in GitHub Desktop.

Select an option

Save orionll/a5db66b5eeb6379d1e1a to your computer and use it in GitHub Desktop.
Remote Procedure Call using Free monads
{-# LANGUAGE DeriveFunctor #-}
import Control.Monad.Free
data Response =
Str { string :: String }
| Boolean { bool :: Bool }
| List { stringList :: [String] }
data Request a = Request String [String] (Response -> a) deriving Functor
type Rpc a = Free Request a
rpc :: String -> [String] -> (Response -> a) -> Rpc a
rpc method params parseResult = fmap parseResult $ liftF $ Request method params id
-- Usage
getFriends :: Rpc [String]
getFriends = do
token <- rpc "login" ["<user>", "<password>"] string
friends <- rpc "friendList" [token] stringList
rpc "logout" [token] bool
return friends
-- Stub interpreter
runStub :: Rpc a -> IO a
runStub (Pure a) = return a
runStub (Free (Request method params onResult)) = do
putStrLn $ "Calling method " ++ method ++ " with params " ++ (show params)
runStub $ onResult $ responseStub method
responseStub :: String -> Response
responseStub "login" = Str "x14yf325j355111"
responseStub "friendList" = List ["John", "David"]
responseStub "logout" = Boolean True
main = runStub getFriends
import scalaz.Free
import scalaz.Functor
case class Request[A](method: String, params: List[Any], onResult: Any => A)
object Rpc {
type Rpc[A] = Free[Request, A]
implicit val rpcFunctor = new Functor[Request] {
def map[A, B](req: Request[A])(f: A => B) = Request(req.method, req.params, r => f(req.onResult(r)))
}
def rpc[A](method: String, params: List[Any]): Rpc[A] = Free.liftF(Request(method, params, _.asInstanceOf[A]))
def run[A](rpc: Rpc[A]): A = ??? // Concrete RPC interpreter (XML-RPC, JSON-RPC, REST, stub ...)
}
object Usage {
import Rpc._
// No dependencies, just pure business logic
val getFriends: Rpc[List[String]] = for {
token <- rpc[String]("login", List("<user>", "<password>"))
friends <- rpc[List[String]]("friendList", List(token))
_ <- rpc[Boolean]("logout", List(token))
} yield friends
println(run(getFriends))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment