7

I wrote this code and it compiles fine

for {
  list : List[Int] <- Future(List(1, 2, 3))
} yield list.size 

res7: Future[Int] = Future(Success(3))

But if I convert this code to

for {
  list : List[Int] <- IO(List(1, 2, 3))
} yield list.size

I get a compile time error

value withFilter is not a member of cats.effect.IO[List[Int]]

If I remove the type then it compiles fine

for {
  list  <- IO(List(1, 2, 3)) // returns IO[List[Int]]
} yield list.size 
res8: IO[Int] = Map(Delay(<function0>), <function1>, 0)

Why can't I specify the type with IO?

I have partial unification enabled so it can't be that :)

Krzysztof Atłasik
  • 21,985
  • 6
  • 54
  • 76
Knows Not Much
  • 30,395
  • 60
  • 197
  • 373
  • 6
    As the error clearly says, **IO** does not have a `withFilter` method. _(You can check the scaladoc [here](https://typelevel.org/cats-effect/api/cats/effect/IO.html))_. When you put the type explicitly, you are basically filtering all elements that match such type. And, since the method does not exists, it won't compile. - And no, I do not know any workaround. – Luis Miguel Mejía Suárez Apr 16 '19 at 19:24
  • So is this a shortcoming of the IO? or there is a reason why withFilter has deliberately been skipped? – Knows Not Much Apr 16 '19 at 19:44
  • 6
    I do not know, I am just an user of **IO**, not a maintainer :) - But, I can think on at least ne reason of why it should not have it. **IO** is not exactly a _"container"_ of elements, _like **List**_, since it only is a description of a computation, and if you ant to see it like a container it will only had one element, _like **Option**_. But, unlike the former, there is not concept of _empty_ **IO**. Thus, filtering an **IO** would not make sense. – Luis Miguel Mejía Suárez Apr 16 '19 at 19:52
  • 4
    You might find this helpful: https://github.com/oleg-py/better-monadic-for#destructuring-either--io--task--flatmapf – slouc Apr 16 '19 at 20:27
  • 2
    Workarounds would be to introduce one more variable `for { list <- IO(List(1, 2, 3)); list1: List[Int] = list } yield list1.size` or desugar for-comprehension `IO(List(1, 2, 3)).map((list: List[Int]) => list.size)` – Dmytro Mitin Apr 16 '19 at 20:29

1 Answers1

15

Your for-comprehension gets desugared to form, which uses function withFilter and because IO doesn't have that method, compilation fails.

Fortunately, there is the compiler plugin better-monadic-for, which solves that problem.

Just add addCompilerPlugin("com.olegpy" %% "better-monadic-for" % "0.3.0") in your build.sbt and you should be fine.

Krzysztof Atłasik
  • 21,985
  • 6
  • 54
  • 76