-
-
Save pvillega/21ab35b67c3b903d84cdf6136391e1b3 to your computer and use it in GitHub Desktop.
// 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? |
Not sure to understand why you need to interprete Trades DSL to HTTP DSL?
@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 :(
and why can't you write Trades.DSL ~> HTTP.DSL
?
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 ;)
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?
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
yes, I see, I was doing it the wrong way around, thanks! you helped a lot! :)
It seems I can't create an interpreter from Trades.DSL to Http.DSL
What does it mean exactly?