Scala方法和更高类型的参数 [英] Scala methods and higher-kinded type parameters

查看:111
本文介绍了Scala方法和更高类型的参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在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 type List[Int]
  • Option - takes a type, e.g. Int, to produce the proper type Option[Int]

这种类型的构造函数通常表示为* -> *.您提供一种类型,然后又得到一种类型.也有其他种类.例如,MapEither需要两种类型来生成适当的类型(例如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)时,编译器会推断SList,并且抱怨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屋!

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