5

I have created two Http4s routes:

class FirstRoutes[F[_] : Async](service: FirstService[F]) extends Http4sDsl[F] {        
  def routes: HttpRoutes[F] = HttpRoutes.of[F] {
        //... some code
  }
}   

class SecondRoutes[F[_] : Async] extends Http4sDsl[F] {            
    def routes: HttpRoutes[F] = HttpRoutes.of[F] {
    //... some code
    }
}

Now in my main method I would like to call this routes like this:

override def run(args: List[String]): IO[ExitCode] =
    for {
      _ <- {
        val app = {
          //...
          val firstRoutes = new FirstRoutes[F](someService)
          val secondRoutes = new SecondRoutes[F]
          (firstRoutes.routes <+> secondRoutes.routes).orNotFound
        }

But when I compile this code I got an error:

Error:(26, 33) value <+> is not a member of org.http4s.HttpRoutes[Server.F]
          (firstRoutes.routes <+> secondRoutes.routes).orNotFound

It is strange for me, because I can normally use this <+> symbol when I use ctrl+space on route class and also I have good imports:

import cats.effect._
import cats.data._
import org.http4s.server.blaze.BlazeServerBuilder
import cats.effect._
import cats.implicits._

Cannot find out how to fix this and use <+> to call route classes. Maybe it is intellij problem? Can someone help me?

Developus
  • 1,400
  • 2
  • 14
  • 50

2 Answers2

6

add this scala option for build.sbt

scalacOptions += "-Ypartial-unification"
恵砂川
  • 198
  • 2
  • 5
3

Maybe you should read http://eed3si9n.com/herding-cats/import-guide.html

https://blog.softwaremill.com/9-tips-about-using-cats-in-scala-you-might-want-to-know-e1bafd365f88 advice 2)

<+> comes from cats.syntax.semigroupk._.

The following code compiles

import cats.effect.{Async, ExitCode, IO}
import cats.syntax.semigroupk._
import org.http4s.HttpRoutes
import org.http4s.dsl.Http4sDsl
import org.http4s.syntax.kleisli._
import scala.language.higherKinds

class App {

  class FirstRoutes[F[_] : Async](service: FirstService[F]) extends Http4sDsl[F] {
    def routes: HttpRoutes[F] = HttpRoutes.of[F] {
      ???
    }
  }

  class SecondRoutes[F[_] : Async] extends Http4sDsl[F] {
    def routes: HttpRoutes[F] = HttpRoutes.of[F] {
      ???
    }
  }

  trait FirstService[F[_]]

  /*override*/ def run[F[_]: Async](args: List[String]): IO[ExitCode] = {
    val someService: FirstService[F] = ???
    for {
      _ <- {
        val app = {
          //...
          val firstRoutes = new FirstRoutes[F](someService)
          val secondRoutes = new SecondRoutes[F]
          (firstRoutes.routes <+> secondRoutes.routes).orNotFound
        }
        IO(???)
      }
    } yield ExitCode(1)
  }
}
Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
  • Hm strange. I copied your imports into my project and it did not help. I also built whole project. Maybe it is problem with intellij cache. I'll check. – Developus Apr 25 '19 at 21:36
  • 1
    @allocer Try `sbt clean compile`. Check that you do not import the same implicit twice (via different imports). – Dmytro Mitin Apr 25 '19 at 21:38
  • Nothing helped with it. Sbt clean compile does not finish beacause of given error. I clean intellij cache also and it nothing changed. Is there any other alias to change `<+>` into calling method? – Developus Apr 25 '19 at 22:02
  • 1
    @allocer `firstRoutes.routes <+> secondRoutes.routes` is syntax for `SemigroupK[Kleisli[OptionT[F, ?], Request[F], ?]].combineK(firstRoutes.routes, secondRoutes.routes)`. – Dmytro Mitin Apr 25 '19 at 22:46
  • 1
    @allocer Also `firstRoutes.routes <+> secondRoutes.routes` can be written as `firstRoutes.routes.<+>(secondRoutes.routes)` or `firstRoutes.routes.$less$plus$greater(secondRoutes.routes)`. – Dmytro Mitin Apr 25 '19 at 22:54