Scala: Making implicit conversion A->B work for Option[A] -> Option[B]

前端 未结 5 996
一个人的身影
一个人的身影 2020-12-14 08:25

I\'m trying to write a function which re-uses the implicit conversions which I have for Object A -> Object B when they are wrapped in an Option in a generic way so that Opti

5条回答
  •  情话喂你
    2020-12-14 08:55

    Here's clue:

    scala> val fooOpt: Option[Bar] = Option(Foo(1))
    fooOpt: Option[Bar] = Some(Bar(1))
    

    And another:

    scala> implicit def foobar(x: String): Int = augmentString(x).toInt
    foobar: (x: String)Int
    
    scala> val y: Option[String] = Option(1)
    y: Option[String] = Some(1)
    
    scala> val y: Option[Int] = Option("1")
    y: Option[Int] = Some(1)
    

    Looks like a legitimately odd bug. I'd pop open a smaller test case and open an issue (or search for one in JIRA).

    As an aside:

    You could use some category theory to handle lots of different types of "Option-ish" things.

    package object fun {
      trait Functor[Container[_]] {
        def fmap[A,B](x: Container[A], f: A => B): Container[B]
      }
      object Functor {
         implicit object optionFunctor extends Functor[Option] {
           override def fmap[A,B](x: Option[A], f: A => B): Option[B] = x map f
         }
         // Note: With some CanBuildFrom magic, we can support Traversables here.
      }
      implicit def liftConversion[F[_], A, B](x: F[A])(implicit f: A => B, functor: Functor[F]): F[B] = 
        functor.fmap(x,f)
    
    }
    

    That's a bit more advanced, as you're mapping some category theory FP onto the problem, but it's a more general solution to lift implicit conversations into containers as needed. Notice how they chain by using one implicit conversation method that takes a more limited implicit argument.

    ALSO, this should make the examples work:

    scala> val tmp = Option(Foo(1))
    tmp: Option[Foo] = Some(Foo(1))
    
    scala> val y: Option[Bar] = tmp
    y: Option[Bar] = Some(Bar(1))
    

    And make your usage of Some more dangerous:

    scala> val tmp = Some(Foo(1))
    tmp: Some[Foo] = Some(Foo(1))
    
    scala> val y: Option[Bar] = tmp
    :25: error: could not find implicit value for parameter functor: fun.Functor[Some]
           val y: Option[Bar] = tmp
                                ^
    

    That's telling you that variance is critical, and interacts with implicits. My guess is you ran into a very rare, probably hard to fix bug that can be avoided using other techniques.

提交回复
热议问题