Search code examples
scalamonadsfunctorscala-cats

value is not a member of type parameter F[]


I have this code:

trait ModelDataService[F[_]] {
  def getModelVersion(modelVersionId: Long): F[ModelVersion]
}

class ModelDataServiceIdInterpreter[F[_] : Monad] extends ModelDataService[F] {
  override def getModelVersion(modelVersionId: Long): F[ModelVersion] = {
    val mv = ModelVersion(1, 1, "ModelType", "Status", None, None, Some(ModelContract("ModelName", Some(ModelSignature("infer", Seq(ModelField(name="blah", profile=DataProfileType.NUMERICAL)), Seq.empty[ModelField])))), None, "", None)
    Monad[F].pure(mv)
  }
}

I am trying to do this:

    val model = modelDataService.getModelVersion(modelVersionId)
    val batchSize = model.monitoringConfiguration

I get a compile error

 value monitoringConfiguration is not a member of type parameter F[a.grpc.entities.ModelVersion]

However, a.grpc.entities.ModelVersion has the monitoringConfiguration field. I guess it has something to do with F. Is there a way I can access the batchSize inside model?


Solution

  • It depends on constraints that you have over your higher-kinded type F. If your F is a functor, then you can access the value inside using map. If F is a FlatMap, or a Monad, you can also use flatMap.

    val batchSize: F[Long] =
      modelDataService
        .getModelVersion(modelVersionId)
        .map(_.monitoringConfiguration)
    
    

    The way the program is structured is that your value will be inside of F at all times, until you really need to get it out. And that is done by initiation of F to some concrete type, e.g. IO from cats-effect, or Future from native scala library. Or if you don't perform any side-effects, it can be as simple as Option. Once the type is concrete, you have different ways of getting the value out, depending on the type. For Future it can be .onComplete, for Option it can be .getOrElse, etc.

    val service: ModelDataService[Option] = new ModelDataServiceIdInterpreter[Option]
    val maybeBatchSize: Option[Long] =
      modelDataService
        .getModelVersion(modelVersionId)
        .map(_.monitoringConfiguration)
    
    val batchSizeDefaultValue = 10L
    val batchSize = maybeBatchSize.getOrElse(batchSizeDefaultValue)