代码之家  ›  专栏  ›  技术社区  ›  Lasf

为一个值和该值的函子编写一个隐式类

  •  2
  • Lasf  · 技术社区  · 6 年前

    我经常发现自己必须对一个值以及该值的函子执行几乎相同的操作。我通常使用两个隐式类来实现这一点,如下所示:

    implicit class Apimped(a: A) {
      def doSomething: B = ???
    }
    
    implicit class FApimped[F[_]: Functor](fa: F[A]) {
      def doSomething: F[B] = Functor[F].map(fa)(a => a.doSomething)
    }
    

    所以我可以这样做,例如:

    a.doSomething //B
    Option(a).doSomething //Option[B]
    

    map 当您调用时,操作将是隐式的 doSomething 关于值的函子。谢谢。

    1 回复  |  直到 6 年前
        1
  •  2
  •   Andrey Tyukin    6 年前

    假设您有来自Scalaz或Cats的这些类型类:

    import scala.language.higherKinds
    
    trait Functor[F[_]] {
      def map[A, B](a: F[A])(f: A => B): F[B]
    }
    
    type Id[X] = X
    implicit object IdFunctor extends Functor[Id] {
      def map[A, B](a: A)(f: A => B): B = f(a)
    }
    implicit object OptionFunctor extends Functor[Option] {
      def map[A, B](a: Option[A])(f: A => B) = a map f
    }
    

    trait EverythingIsAlwaysAFunctor[A, B, F[_]] {
      def apply(a: A): F[B]
      def functor: Functor[F]
    }
    
    object EverythingIsAlwaysAFunctor {
      implicit def functorIsFunctor[A, F[_]](implicit f: Functor[F])
      : EverythingIsAlwaysAFunctor[F[A], A, F] = {
        new EverythingIsAlwaysAFunctor[F[A], A, F] {
          def apply(fa: F[A]): F[A] = fa
          def functor: Functor[F] = f
        }
      }
    
      implicit def idIsAlsoAFunctor[A]
      : EverythingIsAlwaysAFunctor[A, A, Id] = {
        new EverythingIsAlwaysAFunctor[A, A, Id] {
          def apply(a: A): Id[A] = a
          def functor: Functor[Id] = implicitly[Functor[Id]]
        }
      }
    }
    

    1. A 已经成形 F[B] F ,然后使用这个函子
    2. A 实际上是 Id[A]

    现在你可以写你的 DoSomething doSomething 方法:

    implicit class DoSomething[A, F[_]](a: A)(
      implicit eiaaf: EverythingIsAlwaysAFunctor[A, Int, F]
    ) {
      def doSomething: F[String] = eiaaf.functor.map(eiaaf(a))("*" * _)
    }
    

    然后它在所有情况下都有效:

    val x = Option(42).doSomething
    val y = 42.doSomething
    
    println(x)
    println(y)
    

    印刷品:

    Some(******************************************)
    ******************************************