I am writing a DSL using case classes with the help of the cats.free.Free Monad library. The DSL is to be interpreted by Actors receiving the message, so each actor has to first unwrap a command using Free.resume.
This worked out nicely six years ago using scalaz where we also used the resume function too, but the Functor for the free monad was easy to create as we used case classes that came with an extra function argument that could be mapped over such as k below.
case class GetResource[Rdf <: RDF, A](
uri: Rdf#URI,
k: NamedResource[Rdf] => A) extends LDPCommand[Rdf, A]
But the current examples for cats.scala.Free on the cats Free Monad web page don't come with such an argument. And indeed those work nicely when using the interpretation of Free Monads via a natural transformation. I tried this out with a super simple DSL with only one case class
sealed trait LDPCmd[A]:
def url: Uri
case class Get[T](url: Uri) extends LDPCmd[Response[T]]
For which I can then write a simple Script which works as expected in the tests using the natural transformation interpretation.
But with the Actors based interpretation, I now need to unwrap each command in the free monad which gets sent around to different actors using the resume function of Free. This requires a Functor. But it is not clear to me where the functor can get a hold. Ie, what do I put in the ??? position here
given CmdFunctor: cats.Functor[LDPCmd] with
def map[A, B](fa: LDPCmd[A])(f: A => B): LDPCmd[B] = fa match
case g: Get => ???
The answer is it seems to return back to adding the extra function to the case class. On the cats chat channel Rob Norris wrote:
The code he pointed to is SimMessageSocket.scala.