用Functor使用子类调用泛型函数(cats / scalaz) [英] Calling generic function with Functor using subclass (cats/scalaz)

查看:124
本文介绍了用Functor使用子类调用泛型函数(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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆