2

I've probably encountered a version of chained implicit conversions problem (http://docs.scala-lang.org/tutorials/FAQ/chaining-implicits.html). And I cannot figure out how to work it around.

I attached a SSCCE example below which illustrates the issue. Let me add some details here:

1) I want to have a method like the following one:

def chainedTransform[A, B, C](a: A)(f1: F[A, B], f2: F[B, C]): C

It should transform value from type A to type C.

2) It may happen that the transformer F with necessary type parameters is not present in scope, but a satisfying implicit conversion is.

3) The whole approach is demonstrated in the snippet below.

  test("Mutliple conversions") {
    val f1: Function1[String, Int] = (s) => s.toInt
    val f2: Function1[Int, Boolean] = (i) => i > 0
    val f3: Function[Option[Int], Option[Boolean]] = (iOpt) => iOpt map (_ > 0)

    implicit def toOptFun[A, B](f: Function1[A, B]): Function1[Option[A], Option[B]] =
      new Function1[Option[A], Option[B]] {
        override def apply(v1: Option[A]): Option[B] = v1 map f
      }

    case class Test[A](param: A) {
      def transform[B](t1: Function1[A, B]): B = t1(param)
      def chainedTransform[B, C](t1: Function1[A, B], t2: Function1[B, C]): C = t2(t1(param))
    }

    val test1 = Test("123")
    assert(test1.chainedTransform(f1, f2))

    val test2 = Test(Option("123"))
    //toOptFun implicit conversion is applied successfully
    assert(test2.transform(f1) == Some(123))

    //Does not compile: 
    //test2.chainedTransform(f1, f2)
    //  [error]  found   : Int => Boolean
    //  [error]  required: Option[Int] => Boolean
    //  [error]     test2.chainedTransform(f1, f2)
    //  [error]                                ^

    //f3 is exactly what toOptFun(f2) would produce if applied
    assert(test2.chainedTransform(f1, f3) == Some(true))
  }

Any ideas how to make it work?

1 Answer 1

2

This is simply because Scala is trying to go for the wrong type for test2.chainedTransform(f1, f2). As the error message suggests, the compiler is looking for an Option[Int] => Boolean when all you have is an implicit conversion to Option[Int] => Option[Boolean].

If you hint to the compiler what you really want with a type annotation, everything will compile.

test2.chainedTransform(f1, f2): Option[Boolean]

As a side note, chainedTransform is reverse function composition (the andThen method on functions) in the specific case of functions and more generally is reverse composition on arrows (the >>> operator for the Arrow typeclass in Scalaz).

Sign up to request clarification or add additional context in comments.

1 Comment

Are you sure about the Arrow thing? Isn't >>> equivalent of andThen?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.