Scala方法和更高类型的参数 [英] Scala methods and higher-kinded type parameters
问题描述
我试图在Scala中定义一个方法,该方法采用通用类型S[_] <: Seq[Double]
并返回S [FixedLoad](FixedLoad是一种具体类型).但是我的实现给我带来了错误,我不知道为什么.尽管我已经尝试了很多次以了解参数类型和类型更高级的类型,但是我的知识却变得如此缓慢.
I am trying to define a method in scala that takes a generic type of S[_] <: Seq[Double]
and returns a S[FixedLoad] (FixedLoad is a concrete type). But my implementation gives me errors and I can't figure out why. Despite I have tried so many times to understand parametric types and higher-kinded types, my knowledge grows so slow.
我要实现的目标是不丢失S的具体类型(序列子类型).
What I am trying to achieve is to not lose the concrete type of S (the sequence subtype).
这是代码:
import scala.collection.generic.CanBuildFrom
class FixedLoad(val id: Int, val positionInT: Int, val amplitude: Double) {
override def toString: String = s"FixedLoad($id, $positionInT, $amplitude)"
}
object Load {
implicit def toFixedLoads[S[_] <: Seq[Double]](l: S[Double])(implicit cbf: CanBuildFrom[Nothing, FixedLoad, S[FixedLoad]]): S[FixedLoad] = {
l.map(_ => new FixedLoad(1, 1, 1)).to[S]
}
def main(args: Array[String]): Unit = {
println(toFixedLoads(List(1.0, 2.0, 3.0)))
}
}
和错误:
Error:(16, 13) inferred type arguments [List] do not conform to method toFixedLoads's type parameter bounds [S[_] <: Seq[Double]]
println(toFixedLoads(List(1.0, 2.0, 3.0)))
Error:(16, 30) type mismatch;
found : List[Double]
required: S[Double]
println(toFixedLoads(List(1.0, 2.0, 3.0)))
推荐答案
简短答案:
将toFixedLoads[S[_] <: Seq[Double]]
更改为toFixedLoads[S[A] <: Seq[A]]
详细答案:
当您说S[_]
时,这是一种更高种类的类型.或者,换句话说,它是一个类型构造函数.这意味着需要一种类型来产生最终的正确类型.以下是一些示例:
When you say S[_]
, that's a higher kinded type. Or, in other words, it's a type constructor. That means it takes a type to produce the final proper type. Here are some examples:
-
List
-采用一种类型,例如Int
,以产生正确的类型List[Int]
-
Option
-采用一种类型,例如Int
,以产生正确的类型Option[Int]
List
- takes a type, e.g.Int
, to produce the proper typeList[Int]
Option
- takes a type, e.g.Int
, to produce the proper typeOption[Int]
等
这种类型的构造函数通常表示为* -> *
.您提供一种类型,然后又得到一种类型.也有其他种类.例如,Map
和Either
需要两种类型来生成适当的类型(例如Map[Int, String]
或Either[Error, Foo]
),因此它们的类型为* -> * -> *
.将其视为咖喱类型构造函数;接受一个类型并返回一个接受该类型的函数,然后您将获得最终的正确类型.换句话说,需要两种类型来产生最终的正确类型.您可能还需要一个类型构造函数,该类型构造函数需要一个类型构造函数来构建适当的类型(例如Monad[F[_]]
),在这种情况下,该类型为(* -> *) -> *
(例如List -> Monad[List]
).
Type constructors of this kind are often represented as * -> *
. You provide one type and you get a type back. There are other kinds as well; for example, Map
and Either
need two types to produce the proper type (e.g. Map[Int, String]
or Either[Error, Foo]
), so their kind is * -> * -> *
. Think of it as a curried type constructor; takes a type and returns a function that takes a type and then you get the final, proper type. Or in other words, takes two types to produce the final, proper type. You might also have a type constructor that needs a type constructor to build the proper type (e.g. Monad[F[_]]
), in which case the kind is (* -> *) -> *
(for example, List -> Monad[List]
).
因此,当您说您的方法期望参数类型为S[Double]
并传递List(1.0, 2.0, 3.0)
时,编译器会推断S
为List
,并且抱怨List[A]
不是A
).解决该问题的第一个尝试可能是F[_] <: Seq[_]
,但由于内部类型仍然不对齐,因此无法编译.我们需要将它们与F[A] <: Seq[A] for some A
之类的连接"起来,可以将其简单地写为F[A] <: Seq[A]
.
So when you say your method is expecting a parameter of type S[Double]
and you pass List(1.0, 2.0, 3.0)
, compiler infers S
to be List
, and it complains about List[A]
not being a subtype of Seq[Double]
for any A
. Your first attempt at fixing this might be F[_] <: Seq[_]
, but that can't compile, because the inner types still don't align. We need to "connect" them with something like F[A] <: Seq[A] for some A
, which can be written simply as F[A] <: Seq[A]
.
一个好问题可能是我可以说S <: Seq[Double]
吗?"当然,S
代表适当的类型,因此您完全可以!这样的事情就可以了:
A good question might be "can I say S <: Seq[Double]
?" Sure, S
represents a proper type, so you totally could! Something like this works just fine:
def foo[S <: Seq[Double]](s: S) = println(s)
foo(List(1.0, 2.0)) // prints List(1.0, 2.0)
但是,当然,您的S
中有一个洞",因为您的方法参数的类型为S[Double]
,因此不适用于您的情况.
But of course, your S
has a "hole" in it, because your method parameter is of type S[Double]
, so it's not applicable in your case.
这篇关于Scala方法和更高类型的参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!