How to compose monadic functions/methods of type Function1 via 'andThen' in Scala?

Viewed 81

I'm trying to compose functions of types f: a -> Either[_,b] with each other but nothing seems to work. I tried extending Function1 with implicits like below but keep getting compilation errors:

import scala.language.implicitConversions
object MyExtensions {
  implicit class AndThenEither[A,B](val e: Function1[A,Either[_,B]]) {
    def andThen[C](f:Function1[B, Either[_,C]]): Function1[A, Either[_,C]] = {
      (v1: A) => e.apply(v1).flatMap(b => f.apply(b)) //type: A => Either[_,C]
    }
  }
}

However the below fails:

object Sample extends App {

  case class TenX(t: Int)
  case class DoubleX(x: Int)

  def composeFunction1Test(): Unit = {
    val func1: (Int) => Either[String, TenX] = (i: Int) => Right(TenX(10 * i))
    val func2: (TenX) => Either[String, DoubleX] = (t: TenX) => Right(DoubleX(t.t * 2))

    val pipeline = func1 andThen func2 

    val result = pipeline(1); //Expected Right(DoubleX(20))
  }
}

This keeps complaining about a type mismatch and I can't figure out what's wrong. Also, if I try to use it with def defined methods (instead of val like above) it still fails compilation.

Question: How can I compose such Either typed functions with an equivalent andThen operator/function to be used across any such function or class method to allow for such chaining?

1 Answers

Since andThen is already defined on Function1 then implicit resolution will not kick in to resolve extension method of the same name. Try renaming the extension method

implicit class AndThenEither ... {
    def fooAndThen ...
  }

func1 fooAndThen func2 // should work

Kleisli is indeed a way of composing functions returning monadic value.

Related