[Cats-effect] a packet seems to not be part of context

Hi all,
I’m practicing with cats-effect, but I’m facing with a strange compiler error.
This is the exact error:

[error] /full-project-path/createSQLstring.scala:155:54: value ap is not a member of object cats.Applicative
[error]    val outSQLString7 : IO[String] = cats.Applicative.ap(outApplicative)(listaOut);
[error]                                                      ^

value ap is not a member of object cats.Applicative
This is my actual build.sbt file: build-sbt

And this is the main code I’m trying to get up and running, with some of my tries:

ackage src.main.scala.createSQLPackage

//import cats._
import cats.Applicative._ //OK
//import cats.syntax.functor._
import cats.syntax.applicative._
import cats.effect.{IO, Fiber}    //OK
import cats.effect.kernel.Outcome 
//import cats.kernel.Monoid
import cats.effect.syntax.all._

import cats.syntax.all._  //OK
//import cats.Functor._
//import cats.Applicative._   
//import cats.kernel.Semigroup  
//import cats.kernel.Monoid   
//import cats.effect.IO;

import cats.effect.instances.all

import src.main.scala.computeMD5Package;

import cats.effect.unsafe.implicits.global

class setSQLRecord(listaZipped : List[IO[Fiber[IO, Throwable, String]]],
                   timeMarkFiber : IO[Fiber[IO, Throwable, String]],
                   volume : IO[Int]) { 

   val concatenaSQLstringValue : List[String] => String = item => concatenaSQLstring(item);
   val outApplicative : IO[List[String] => String] = IO(concatenaSQLstringValue);
   //val outSQLString : IO[String] = listaOut.ap(outApplicative);
   //val outSQLString2 : IO[String] = cats.Applicative.ap(outApplicative)(listaOut);
   //val outSQLString3 : IO[String] = cats.Functor.compose(listaOut, outApplicative);
   //val outSQLString4 : IO[String] = org.typelevel:`cats-core_2.12:2.9.0`.Functor.compose(listaOut, outApplicative);
   //val outSQLString5 : IO[String] = org.typelevel:`cats-effect_2.12:3.4.5`.Applicative.ap(outApplicative)(listaOut);
   //val outSQLString6 : IO[String] = cats.Applicative.ap(outApplicative)(listaOut);
   val outSQLString7 : IO[String] = cats.Applicative.ap(outApplicative)(listaOut);
   //val outSQLString8 : IO[String] = listaOut.org.typelevel:`cats-core_2.12:2.9.0`.Applicative.ap(outApplicative);

I’m not able to figure out wich is the exact sequence of imports to get “ap” or “Functor.compose” be available in my code.

Thank you

I know nothing about cats but here’s what I can tell:

Here it looks like ap is a method on an instance of trait Applicative.

Whereas cats.Applicative is a companion object, and does not have an ap function.

So if your outApplicative is an instance of trait Applicative (since it’s an instance of IO I assume it must be), then outApplicative.ap(...) might work, give that a try maybe?

Backing off for a second: what are you trying to accomplish here?

@spamegg1 is correct that ap is a method on a trait, not an object, so you can’t just call it like that – it’s going to be a method on an object.

More than that, though, Applicative (like much of cats) is a type class – in Java terms, basically an adapter object. So while he’s right that you would probably use the Applicative for IO, that doesn’t mean that IO is itself an Applicative, it means than an Applicative exists for IO, and you summon it implicitly.

(It’s actually very rare to call ap directly – it’s mainly there to be called by other functions.)

I’m worried that you may be jumping ahead too quickly – this is really cats stuff, rather than cats-effect. If you haven’t done a lot with type classes yet, I’d recommend going through the cats documentation (really, I’d recommend a quick read through the short book Scala With Cats) to get comfortable with the type classes and how they work before trying to play with advanced stuff like this.

(Note: you don’t need to know all of this in order to work with cats-effect – I’ve never once actually used ap directly in cats-effect application code. Most of this stuff is under the hood, intended more for library authors, and can/should be ignored when you’re getting started. You can do an awful lot with IO before really grokking what’s going on under the hood.)

1 Like

Correct ! I’m not expert. I just have an
IO[List[String]] and need an IO[String] concatenating all the strings in the list itself. I thought that could use an applicative to extract, concat and wrab back in the IO. Otherways a Functor.compose . In every case this error blocks me. It seems that both Functor and Applicative, are not part of the context.

ioListStrings.map(listStrings => listStrings.mkString

That is all you need, just follow the types.
No need to do anything complex.

@BalmungSan beat me to it. Yeah, there’s no need to go anywhere near those complexities – it’s just a map.

1 Like

Actually, it’s worth talking about why that’s the right answer. Think of it this way:

An IO is, more or less exactly, an encapsulated algorithm. It’s called “IO” for historical reasons, but that’s the heart of it: it describes a process that will product a result of a particular type. And the map method on it says what to do next once you have that result – giving you a larger algorithm with that step added.

So your IO[List[String]] is algorithm saying how to get a List[String]. By calling map, you’re saying to take that result, call mkString on it (to concatenate it), and now you have the final IO[String].

That’s the essence of most cats-effect programming – just mapping and flatMapping IOs, building from smaller to larger algorithms until you have the entire program.

1 Like