仅对带有类标签的参数实施函子映射

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

我具有以下数据结构:

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

我目前认为在这种情况下不变形是一种解决方法...

scala functional-programming functor shapeless scala-cats
1个回答
3
投票
Functor

cats.Functor描述了

Scala类型中的endofunctor]-也就是说,您应该能够使用函数mapA => B,其中AB必须支持任何Scala类型。

您拥有的是一个数学函子,但具有ClassTag的类型是另一种较小的类型。这些通用仿函数并不常见-我认为对于stdlib类型,只有SortedSet可以用作一类有序事物的仿函数-因此,目前在Scala FP中这是一个尚未开发的领域,仅在Scalaz 8中有传言。

猫没有任何工具可以对此类事物进行抽象,因此您将不会获得任何实用程序方法和生态系统支持。如果要自己滚动,可以使用that answer linked by @DmytroMitin

Coyoneda

Coyoneda可以使任何类型构造函数F[_]的Scala类型成为endofunctor。这个想法很简单:

具有一些初始值F[Initial]

    具有功能Initial => A
  • 对于mapA => B,您无需触摸初始值,而只需编写函数即可获得Initial => B
  • 您可以将任何F[A]提升到cats.free.Coyoneda[F, A]。问题是如何将F[A]取出。
  • 如果Fcats.Functor,那么可以使用它的本机map是很自然的,实际上,使用CoyonedaF的结果不会有任何区别。直接根据函子定律(x.map(f).map(g) <-> x.map(f andThen g))。

    就您而言,不是。但是您可以将cats.free.Coyoneda拆开,然后委派给自己的map

    def coy[A](fa: MyDaSt[A]): Coyoneda[MyDaSt, A] = Coyoneda.lift(fa) def unCoy[A: ClassTag](fa: Coyoneda[MyDaSt, A]): MyDaSt[A] = fa.fi.map(fa.k) // fi is initial value, k is the composed function

    将允许您使用期望cats.Functor的功能:

    def generic[F[_]: Functor, A: Show](fa: F[A]): F[String] = fa.map(_.show)
    
    unCoy(generic(coy(v))) // ok, though cumbersome and needs -Ypartial-unification on scala prior to 2.13
    

    (可运行示例on scastie

    一个明显的局限性是,您需要在要调用ClassTag[A]的任何位置都具有一个unCo-即使您首先不需要使用它[ MyDaSt[A]的实例。 

    不太明显的是,您不会自动保证没有行为差异。是否可以,取决于您的map所做的事情-例如如果只是分配一些Array,就不会引起问题。

  • © www.soinside.com 2019 - 2024. All rights reserved.