简体   繁体   English

Scala:隐式类的多个类型参数

[英]Scala: Multiple type parameters for implicit class

I'm trying to port parts of a Haskell library for datatype-generic programming to Scala. 我正在尝试将Haskell库的某些部分用于数据类型通用编程移植到Scala。 Here's the problem I've run into: 这是我遇到的问题:

I've defined a trait, Generic , with some container-type parameter: 我用一个容器类型的参数定义了特征Generic

trait Generic[G[_]] {
     // Some function declarations go here
 }

Now I have an abstract class, Collect , with three type parameters, and a function declaration (it signifies a type than can collect all subvalues of type B into a container of type F[_] from some structure of type A ): 现在,我有了一个抽象类Collect ,它带有三个类型参数和一个函数声明(它表示一个类型,可以将类型B所有子值从类型A某些结构收集到类型F[_]的容器中):

abstract class Collect[F[_],B,A] {
  def collect_ : A => F[B]
}

In order to make it extend Generic, the first two type parameters F[_] and B are given, and A is curried (this effect is simulated using type lambdas): 为了使它扩展泛型,给出了前两个类型参数F[_]B ,并且对A进行了咖喱(使用lambda类型模拟此效果):

class CollectC[F[_],B] extends Generic[({type C[A] = Collect[F,B,A]})#C] {
    // Function definitions go here
}

The problem is that I need the last class definition to be implicit, because later on in my code I will need to be able to write functions like 问题是我需要隐式最后一个类定义,因为稍后在代码中,我将需要能够编写类似

class GUnit[G[_]](implicit gg: Generic[G]) {
    // Some definitions
}

When I simply prepend implicit to the class definition, I get the an error saying implicit classes must accept exactly one primary constructor parameter . 当我简单implicitimplicit到类定义之前时,我得到一个错误,提示implicit classes must accept exactly one primary constructor parameter Has anyone encountered a similar problem? 有没有人遇到过类似的问题? Is there a known way to work around it? 有已知的解决方法吗? I don't currently see how I could refactor my code while keeping the same functionality, so any advice is welcome. 我目前看不到如何在保持相同功能的情况下重构代码,因此欢迎您提出任何建议。 Thanks in advance! 提前致谢!

Implicit classes don't work that way. 隐式类不能那样工作。 They are a shorthand for implicit conversions . 它们是隐式转换的简写。 For instance implicit class Foo(i: Int) is equal to class Foo(i: Int); implicit def Foo(i: Int) = new Foo(i) 例如, implicit class Foo(i: Int)等于class Foo(i: Int); implicit def Foo(i: Int) = new Foo(i) class Foo(i: Int); implicit def Foo(i: Int) = new Foo(i) . class Foo(i: Int); implicit def Foo(i: Int) = new Foo(i) So it only works with classes that have exactly one parameter in their constructor. 因此,它仅适用于在其构造函数中仅具有一个参数的类。 It would not make sense for most 0 parameter (type-)classes. 对于大多数0参数(类型)类而言,这没有意义。

The title of your question also seems to suggest that you think the compilation error is talking about type parameters of the type constructor, but I hope the above paragraph also makes clear that it is actually talking about value parameters of the value constructor. 您的问题的标题似乎还表明您认为编译错误是在谈论类型构造函数的类型参数,但我希望以上段落也清楚地表明,它实际上是在谈论价值构造函数的参数。

For what (I think) you are trying to do, you will have to provide an implicit instance of CollectC yourself. 对于您想做的事情(我认为),您必须自己提供一个CollectC的隐式实例。 I suggest putting it in the companion object of Collect . 我建议将其放在Collect的伴随对象中。 But you can choose an alternative solution if that fits your needs better. 但是,如果您更适合您,则可以选择其他解决方案

scala> :paste
// Entering paste mode (ctrl-D to finish)

trait Generic[G[_]] {
  // Some function declarations go here
}

abstract class Collect[F[_],B,A] {
  def collect_ : A => F[B]
}

object Collect {
  implicit def mkCollectC[F[_],B]: CollectC[F,B] = new CollectC[F,B]
}

class CollectC[F[_],B] extends Generic[({type C[A] = Collect[F,B,A]})#C] {
  // Function definitions go here
}

// Exiting paste mode, now interpreting.

warning: there were four feature warnings; for details, enable `:setting -feature' or `:replay -feature'
defined trait Generic
defined class Collect
defined object Collect
defined class CollectC

scala> implicitly[Generic[({type C[X] = Collect[List,Int,X]})#C]]
res0: Generic[[X]Collect[[+A]List[A],Int,X]] = CollectC@12e8fb82

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

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