用Functor使用子类调用泛型函数(cats / scalaz) [英] Calling generic function with Functor using subclass (cats/scalaz)
问题描述
是否可以使用Functor视图(<$ c $)调用一个采用上下文化值( F [A]
)的泛化函数c> F [_]:Functor )的上下文是<:F
?我知道Functor对于 F [_]
类型是不变的,我也知道存在 Functor.widen
,但似乎很奇怪,没有办法隐式扩展我的类型以用于一般函数。
Cat中的一个例子Scalaz也存在):
import cats.instances.all._
import cats.syntax.all._
$ b $ def defucesunctor [F [_]:cats.Functor](f:F [Int])= f.map(_ + 1)
takesAFunctor(Option(1 ))//正常工作(当然)
takesAFunctor(Some(1))//对Functor [Some]没有隐式。有道理,但是我们可以召唤一个,因为我们有一个Functor [Option]?
takesAFunctor(Some(1):Option [Int])//工作但非常详细
当然,显式地召唤Functor for Option并且映射按预期工作
Functor [Option] .map(Some(1) )(_ + 1)//一些(2)
所以我的问题是:签名一般函数需要改变以说明子类的上下文,是否存在某种我不知道的隐式扩展,或者这仅仅是使用stdlib在Scala中进行函数式编程的一个不幸的缺点?
Dmytro的回答指出,这通常是不可能的。这就是cats / scalaz公开一个类型为返回 Option
的 .some
扩展方法的原因,而使用一些
构造函数返回一些
;
takesAFunctor(1.some)
或者,您可以使用更一般的应用
语法; takesAFunctor(1.pure [Option])
是否有某种隐含的扩展,我不知道,或者这是使用stdlib在Scala中函数式编程的一个不幸的缺点?
在手动召唤选项仿函数时,您看到的隐式展宽是协方差。这个实例被不变地定义为 Option
,这就是为什么 Some
是不可接受的 - 编译器找不到隐式,但 Functor [Option] .map
需要一个 Option
或任何子类型 code $>,这就是为什么一些工作。
这里提到的缺点基本上是java-ish covariant子类型和更多haskell- ish不变地键入了类型类型
I've been messing around with some basic examples of Cats/Scalaz and also walking through tutorials to get a feel and I've hit a case which I'm sure there is a solution to.
Is it possible to call a generalized function that takes a contextualized value (F[A]
) with a Functor view (F[_] : Functor
) with a context that is <: F
? I'm aware that Functor is invariant on type F[_]
, and I'm also aware of the existence of Functor.widen
, but it seems strange that there is no way to implicitly widen my type for use in a general function.
An example in Cats (a similar example with Scalaz exists as well):
import cats.instances.all._
import cats.syntax.all._
def takesAFunctor[F[_] : cats.Functor](f: F[Int]) = f.map(_ + 1)
takesAFunctor(Option(1)) // Works fine (of course)
takesAFunctor(Some(1)) // No implicit for Functor[Some]. Makes sense, but can we summon one since we have a Functor[Option]?
takesAFunctor(Some(1): Option[Int]) // Works but very verbose
Of course, summoning the Functor for Option explicitly and mapping works as expected
Functor[Option].map(Some(1))(_ + 1) // Some(2)
So my question is: Does the signature of the general function need to change to account for the subclassed context, is there some sort of "implicit widening" that I don't know about, or is this just an unfortunate drawback to functional programming in Scala using the stdlib?
This isn't generally possible as Dmytro's answer points out. This is the reason that cats/scalaz exposes a .some
extension method that is typed as returning Option
, whereas using the Some
constructor returns Some
;
takesAFunctor(1.some)
Alternately you can use the more general Apply
syntax; takesAFunctor(1.pure[Option])
is there some sort of "implicit widening" that I don't know about, or is this just an unfortunate drawback to functional programming in Scala using the stdlib?
The implicit widening you see when summoning the Option functor manually is covariance. The instance is defined invariantly for Option
which is why Some
isn't acceptable - the compiler can't find the implicit, but Functor[Option].map
expects an Option
or any subtype of Option
, which is why Some works.
The drawback that you mention here is basically an impedance mismatch between the java-ish covariant subtyping and the more haskell-ish invariantly typed typeclasses
这篇关于用Functor使用子类调用泛型函数(cats / scalaz)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!