Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 不应该’;难道不是协变的吗?尤其是在左边?_Scala_Functional Programming_Scala Cats - Fatal编程技术网

Scala 不应该’;难道不是协变的吗?尤其是在左边?

Scala 不应该’;难道不是协变的吗?尤其是在左边?,scala,functional-programming,scala-cats,Scala,Functional Programming,Scala Cats,我有以下代码 def addKitten(kitten: Kitten): EitherT[Future, GenericError, UUID] = { val futureOfEither = db.run { // returns a Future[Int] with the number of rows written kittens += kitten }.map { case 1 => kitten.uuid.asRight case _ =&g

我有以下代码

def addKitten(kitten: Kitten): EitherT[Future, GenericError, UUID] = {
  val futureOfEither = db.run { // returns a Future[Int] with the number of rows written
    kittens += kitten
  }.map {
    case 1 => kitten.uuid.asRight
    case _ => GenericError.SpecificError.asLeft
  }
  EitherT(futureOfEither)
}
其中
SpecificError
GenericError
的子类。出于某种原因,它不会编译,抱怨
特定错误
不是
一般错误
。是这样吗


我的意思是,
或者[A,B]
应该是不可变的,那么为什么不让它协变呢?我遗漏了什么吗?

好的,我找到了解决办法

我仍然不知道为什么
EitherT
不是协变的,但是你必须记住
或者
本身是协变的。
因此,诀窍是告诉编译器为
EitherT
创建使用上限:

EitherT[Future, GenericError, UUID](futureOfEither)
保留多个错误也可以(因为编译器被迫找到LUB),但是
GenericError
必须扩展
Product
Serializable
,如果这是一个特征,并且
SpecificError
是一个case类(请参阅)


XorT
option
提出了相同的问题。答复是:

在Scala中,方差既有正数也有负数(也许这就是他们决定使用方差表示法的原因!:p)。这些优点/缺点在不同的场合已经讨论过无数次,所以我现在就不讨论了,但在我看来,在一天结束时,你必须“各自为政”

我认为这种“各自为政”的观点意味着不能强制类型构造函数发生变化。一个具体的例子是7.0系列中的
scalaz.Free
。它强制
S
类型构造函数是协变的。当时我经常想把一个
Coyoneda
包装成
Free
。最新版本的Cats和Scalaz将
Coyoneda
基本内置于
Free
中,因此这种特殊用途现在可能并不理想,但一般原则适用。问题是,
Coyoneda
是不变的,所以你根本无法做到这一点(没有一堆
@uncheckedVariance
)!通过使类型构造函数参数不变,最终可能会迫使人们对类型更加明确,但我认为这比另一种方法要好,在这种方法中,您可以阻止他们使用您的类型


作为另一个非常简洁的解决方法,您可以在
flatMap[E,T]
type参数中指定抽象类型,例如:

// Given ADT
trait Err
case class E1() extends Err
case class E2() extends Err
// We could do (pseudo-code)
EitherT(E1()).flatMap[Err, Int] { x => 100 }

这是在
FlatMap
的情况下。对于
Map
,您只能在右侧转换值和输入

在Scala Future中,已经包装了一个
Scala.util.Try
,它可能是
Error
或其他什么,我不确定为什么有时候会选择
Future[nother]
,但除了更多的CPU周期和运行时复杂性之外,它没有带来任何好处。@flavian Try的“失败”总是一个不明确的“一次性”而“未来”则是“未来”[Orther]“允许您为错误添加类型约束。您可以将特定于应用程序的错误移到“Orther”并保留“Future.failed”用于致命的基础结构错误,从而在致命错误和预期错误之间实现清晰的分离。您已经可以使用
异常
可丢弃
,因此它仍然只是样板文件。Scala还为您提供
Scala.util.control.NonFatal
// Given ADT
trait Err
case class E1() extends Err
case class E2() extends Err
// We could do (pseudo-code)
EitherT(E1()).flatMap[Err, Int] { x => 100 }