简体   繁体   English

Scala方法和更高级的类型参数

[英]Scala methods and higher-kinded type parameters

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). 我试图在scala中定义一个方法,它采用泛型类型S[_] <: Seq[Double]并返回S [FixedLoad](FixedLoad是具体类型)。 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. 尽管我已经尝试了很多次来理解参数类型和更高级的类型,但我的知识变得如此缓慢。

What I am trying to achieve is to not lose the concrete type of S (the sequence subtype). 我想要实现的是不丢失具体类型的S(序列子类型)。

Here is the code: 这是代码:

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)))
  }

}

and the errors: 和错误:

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)))

Short answer: 简短回答:

Change toFixedLoads[S[_] <: Seq[Double]] to toFixedLoads[S[A] <: Seq[A]] toFixedLoads[S[_] <: Seq[Double]]更改为toFixedLoads[S[A] <: Seq[A]]

Long answer: 答案很长:

When you say S[_] , that's a higher kinded type . 当你说S[_] ,这是一个更高的kinded类型 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 - takes a type, eg Int , to produce the proper type List[Int] List - 获取一个类型,例如Int ,以生成正确的类型List[Int]
  • Option - takes a type, eg Int , to produce the proper type Option[Int] Option - 采用类型(例如Int )生成正确的类型Option[Int]

etc. 等等

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 (eg Map[Int, String] or Either[Error, Foo] ), so their kind is * -> * -> * . 例如, MapEither需要两种类型来生成正确的类型(例如Map[Int, String]或者Either[Error, Foo] ),所以它们的种类是* -> * -> * 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 (eg Monad[F[_]] ), in which case the kind is (* -> *) -> * (for example, List -> Monad[List] ). 您可能还有一个类型构造函数需要一个类型构造函数来构建正确的类型(例如Monad[F[_]] ),在这种情况下,类型是(* -> *) -> * (例如, List -> Monad[List] )。

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 . 因此,当你说你的方法期望一个S[Double]类型的参数并且你传递List(1.0, 2.0, 3.0) 1.0,2.0,3.0 List(1.0, 2.0, 3.0) ,编译器推断SList ,并且它抱怨List[A]不是Seq[Double]的子类型Seq[Double]任何A Seq[Double] Your first attempt at fixing this might be F[_] <: Seq[_] , but that can't compile, because the inner types still don't align. 你第一次尝试修复它可能是F[_] <: Seq[_] ,但是无法编译,因为内部类型仍然没有对齐。 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] . F[A] <: Seq[A] for some A ,我们需要将它们与F[A] <: Seq[A] for some A类的东西“连接”起来,这可以简单地写成F[A] <: Seq[A]

A good question might be "can I say S <: Seq[Double] ?" 一个好问题可能是“我可以说S <: Seq[Double] ?” Sure, S represents a proper type, so you totally could! 当然, S代表一种合适的类型,所以你完全可以! 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)

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. 但是当然,你的S有一个“洞”,因为你的方法参数是S[Double]类型,所以它不适用于你的情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM