import cats._
import cats.syntax.all._
import cats.effect._
import effectie.cats.ConsoleEffectful._
import effectie.cats.Effectful._
import effectie.cats.EitherTSupport._
import effectie.cats.OptionTSupport._
import effectie.cats._
trait Something[F[_]] {
  def foo[A: Semigroup](a: A): F[A]
  def bar[A: Semigroup](a: Option[A]): F[Option[A]]
  def baz[A, B: Semigroup](a: Either[A, B]): F[Either[A, B]]
}
object Something {
  def apply[F[_]: Something]: Something[F] =
    implicitly[Something[F]]
  implicit def something[F[_]: Fx: ConsoleEffect: Monad]: Something[F] =
    new SomethingF[F]
  final class SomethingF[F[_]: Fx: ConsoleEffect: Monad]
    extends Something[F] {
    override def foo[A: Semigroup](a: A): F[A] =
      for {
        n    <- effectOf(a)
        blah <- pureOf("blah blah")
        _    <- effectOf(println(s"n: $n / BLAH: $blah"))
        x    <- effectOf(n |+| n)
        _    <- putStrLn(s"x: $x")
      } yield x
    override def bar[A: Semigroup](a: Option[A]): F[Option[A]] =
      (for {
        aa   <- a.optionT[F] 
        blah <- "blah blah".someTF[F] 
        _    <- effectOf(
                  println(s"a: $a / BLAH: $blah")
                ).someT 
        x    <- effectOf(a |+| a).optionT 
        _    <- effectOf(putStrLn(s"x: $x")).someT 
      } yield x).value
    override def baz[A, B: Semigroup](ab: Either[A, B]): F[Either[A, B]] =
      (for {
        b    <- ab.eitherT[F] 
        blah <- "blah blah"
                  .asRight[A]
                  .eitherT[F] 
        _    <- effectOf(
                  println(s"b: $b / BLAH: $blah")
                ).rightT[A] 
        x    <- effectOf(ab |+| ab).eitherT 
        _    <- effectOf(
                  putStrLn(s"x: $x")
                ).rightT[A] 
      } yield x).value
  }
}
println(Something[IO].foo(1).unsafeRunSync())
println(Something[IO].bar(2.some).unsafeRunSync())
println(Something[IO].bar(none[String]).unsafeRunSync())
println(Something[IO].baz(2.asRight[String]).unsafeRunSync())
println(Something[IO].baz("ERROR!!!".asLeft[Int]).unsafeRunSync())