Skip to content

Instantly share code, notes, and snippets.

@pvillega
Created June 5, 2016 20:58
Show Gist options
  • Save pvillega/21ab35b67c3b903d84cdf6136391e1b3 to your computer and use it in GitHub Desktop.
Save pvillega/21ab35b67c3b903d84cdf6136391e1b3 to your computer and use it in GitHub Desktop.
Can we merge the interpreters?
// simplified code to give the idea. Starting with 2 DSL, Trades and Http
object Trades {
sealed trait DSL[A] { def url: String }
final case class HeartBeat() extends DSL[TradeResult[StatusOk]]
type TradesPRG[A] = (DSL :|: FXNil)#Cop[A]
}
object Http {
sealed trait DSL[A]
final case class Get(url: String, parameters: Map[String, List[String]]) extends DSL[Result]
type HttpPRG[A] = (DSL :|: FXNil)#Cop[A]
val executerInterpreter: Interpreter[HttpPRG, Task] = AsyncHttpInterpreter
// I need this alias for interpreters, see comments below
type HttpFree[A] = Free[HttpPRG, A]
}
// Now we define an interpreter from Http to AsyncHttp (some code omitted for brevity)
object AsyncHttpInterpreter extends (Http.DSL ~> Task) {
import Http._
def apply[A](a: Http.DSL[A]) = a match {
case Get(url, parameters) => get(url, parameters)
}
}
// It seems I can't create an interpreter from Trades.DSL to Http.DSL, instead I need to go from Trades.DSL to Http.HttpFree
object TradesHttpInterpreter extends (Trades.DSL ~> Http.HttpFree) {
import Trades._
import Http._
def apply[A](a: Trades.DSL[A]) = a match {
case o @ HeartBeat() =>
val x: Free[HttpPRG, Result] = for {
rsp <- Get(o.url, Map.empty[String, List[String]]).freek[HttpPRG]
} yield rsp
x.map(rslt => StatusOk().asInstanceOf[A].right)
}
}
// To run a program them it seems I can't combine the interpreters I have, but I need to run 2 foldmap in a row
// (compile fails when trying to compose them)
localProgram
.foldMap(TradesHttpInterpreter.nat).foldMap(Http.executerInterpreter.nat)
.runAsync
// Is there any way to combine TradesHttpInterpreter and Http.executerInterpreter in a single interpreter?
@mandubian
Copy link

Not sure to understand why you need to interprete Trades DSL to HTTP DSL?

@pvillega
Copy link
Author

pvillega commented Jun 5, 2016

@mandubian I'm trying to build a stack similar to what I did before in my experiments, using cats.Free.

The idea is I can define an Http language which may be tailored to needs and well tested, and then use it to define things 'at a higher level', in this case Trade operations. I could later refactor the Http language interpreters and that would propagate the changes to all the Free that rely on it.

With cats.Free I could compose the interpreters, but in here when I try to:

val composedInterpreter = Http.executerInterpreter.nat compose TradesHttpInterpreter.nat

it doesn't work, and I'm at a loss why :(

@mandubian
Copy link

and why can't you write Trades.DSL ~> HTTP.DSL ?

@mandubian
Copy link

ok I catch what you want to do... you want to "lift" all DSL to HTTP and then do calls and finally get results...
But I don't understand why you can't write Trades.DSL ~> HTTP.DSL
because your Trades.DSL ~> Http.HttpFree isn't necessarily bad but it smells like Trades.DSL ~> HTTP.DSL would be more logical or I miss something ;)

@pvillega
Copy link
Author

pvillega commented Jun 6, 2016

My only question (may be a misunderstanding on my part), if I do Trades.DSL ~> HTTP.DSL then how do I work with the Results of Http.DSL?

So if I want to define an operation HeartBeat() from Trades.DSL as a GET + parsing the return json to an object HeartbeatResult, how do I define that? Won't I need the HttpFree for that?

@mandubian
Copy link

it certainly means you want to :
1/ convert result of Http to TradesResult : Trades.DSL ~> Http.DSL ~> TradesResult.DSL
2/ combine Trades.DSL & Http.DSL in your program as a Coproduct Trades.DSL :|: Http.DSL

@pvillega
Copy link
Author

pvillega commented Jun 7, 2016

yes, I see, I was doing it the wrong way around, thanks! you helped a lot! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment