【发布时间】:2019-12-05 09:58:08
【问题描述】:
我有以下数据结构:
class MyDaSt[A]{
def map[B: ClassTag](f: A => B) = //...
}
我想实现一个Functor 实例,以便能够使用临时多态性。显而易见的尝试如下:
implicit val mydastFunctor: Functor[MyDaSt] = new Functor[MyDaSt] {
override def map[A, B](fa: MyDaSt[A])(f: A => B): MyDaSt[B] = fa.map(f) //compile error
}
它显然无法编译,因为我们没有提供隐式ClassTag[B]。但是是否可以仅将map 与函数f: A => B 一起使用,这样就有ClassTag[B]。否则编译错误。我的意思是这样的:
def someFun[A, B, C[_]: Functor](cc: C[A], f: A => B) = cc.map(f)
val f: Int => Int = //...
val v: MyDaSt[Int] = //...
someFunc(v, f) //fine, ClassTag[Int] exists and in scope
无论如何我都无法更改它的实现,但我可以创建包装器(通过它看起来没有帮助)或继承。我可以随意使用任何版本的shapeless。
我目前认为在这种情况下无形是一种方法......
【问题讨论】:
-
简短的回答是你不能。首先,它会是一个有缺陷的Functor,因为它不支持任何
A => B而是ClassTag[B] -> A => B(它是前一个的子集)。其次,如果 Functor 从 cats 你不能改变签名。最后,在您的通用示例中,没有办法将ClassTag传递给调用。 -
@LuisMiguelMejíaSuárez 所以在数据结构中使用这样的签名声明
map会抑制函子语义...... -
AFAIK 是的,至少是完全合法的。您可以创建自己的
TaggedFunctor,其map始终需要ClassTag,然后您提供implicit def fromCatsFunctorToTaggedFunctor[F[_]](implicit functor: cats.Functor): TaggedFunctor[F] = ...,您需要使用隐式优先级,您将失去所有cats 提供,但您将重新获得编写通用函数的能力。 - PS:如果有更好的方法,值得在猫 gitter 房间询问。 -
@SomeName 你总是可以用
def map[B: ClassTag](f: A => B)创建MyDaSt。问题是为什么你需要它成为Functor。如果它是Functor,你会如何使用它?你能添加一些代码吗?有时你可以使用cats.free.Coyoneda。
标签: scala functional-programming functor shapeless scala-cats