为该值的值和仿函数编写单个隐式类

问题描述 投票:2回答:1

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

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操作将是隐含的。谢谢。

scala scala-cats
1个回答
2
投票

我不知道它是否在Scalaz / Cats中(也许,不能保证它不存在),但原则上它确实有效。这是一个没有任何依赖的小演示,演示了原理。

假设您有来自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-pimp-my-library-syntax事物:

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(******************************************)
******************************************
© www.soinside.com 2019 - 2024. All rights reserved.