Search code examples
scalatypesscala-cats

How to express type bound that forces the type param to behave like functor


I'm struggling to write a method that operates on either Free Monad to Tagles Final. I would like to use type class to pass an interpreter that produces a Monad. In the same function I would like to use map function.

I don't know how to express type bound so that the M type is a functor or monad.

import cats._
import cats.free.Free

def eval[M[_]](param: String)(implicit op: Algebra ~> M): M[String] {
  val program: Free[Algebra, String] = Free.liftF(Operation(param))
  Free.foldMap(op)
}

def process[M[_]](param: String)(implicit op: Algebra ~> M): M[String] {
   val result = eval(param)
   result.map(_.toUpper) //this doesn't compile because M is missing map method
}

Solution

  • Try

    import cats.{Monad, ~>}
    import cats.free.Free
    import cats.syntax.functor._
    
    import scala.language.higherKinds
    
    trait Algebra[_]
    
    case class Operation(str: String) extends Algebra[String]
    
    def eval[M[_]: Monad](param: String)(implicit op: Algebra ~> M): M[String] = {
      val program: Free[Algebra, String] = Free.liftF (Operation (param) )
      Free.foldMap(op).apply(program)
    }
    
    def process[M[_]: Monad](param: String)(implicit op: Algebra ~> M): M[String] = {
      val result = eval(param)
      result.map(_.toUpperCase)
    }