Scala:隐式 class 的多个类型参数
Scala: Multiple type parameters for implicit class
我正在尝试将用于数据类型通用编程的 Haskell 库的一部分移植到 Scala。这是我 运行 遇到的问题:
我定义了一个特征,Generic
,带有一些容器类型的参数:
trait Generic[G[_]] {
// Some function declarations go here
}
现在我有一个抽象 class、Collect
,具有三个类型参数和一个函数声明(它表示一个类型,可以将类型 B
的所有子值收集到一个F[_]
类型的容器,来自 A
类型的某些结构):
abstract class Collect[F[_],B,A] {
def collect_ : A => F[B]
}
为了使其扩展Generic,给出了前两个类型参数F[_]
和B
,并柯里化了A
(这个效果是使用type lambdas模拟的):
class CollectC[F[_],B] extends Generic[({type C[A] = Collect[F,B,A]})#C] {
// Function definitions go here
}
问题是我需要隐式的最后一个 class 定义,因为稍后在我的代码中我需要能够编写像
这样的函数
class GUnit[G[_]](implicit gg: Generic[G]) {
// Some definitions
}
当我简单地将 implicit
添加到 class 定义之前时,我得到一个错误 implicit classes must accept exactly one primary constructor parameter
。有没有人遇到过类似的问题?有没有一种已知的方法来解决它?我目前不知道如何在保持相同功能的同时重构我的代码,因此欢迎任何建议。提前致谢!
隐式 类 不会那样工作。它们是隐式 转换 的 shorthand。例如 implicit class Foo(i: Int)
等于 class Foo(i: Int); implicit def Foo(i: Int) = new Foo(i)
。所以它只适用于 类 ,它们的构造函数中只有一个参数。对于大多数 0 参数 (type-)类.
没有意义
你的问题的标题似乎也暗示你认为编译错误是在谈论类型构造函数的类型参数,但我希望上面的段落也说明它实际上是在谈论 value 构造函数的 value 参数。
对于(我认为)您正在尝试做的事情,您必须自己提供 CollectC
的隐式实例。我建议将它放在 Collect
的同伴 object 中。但如果更符合您的需要,您可以选择 alternative solution。
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
我正在尝试将用于数据类型通用编程的 Haskell 库的一部分移植到 Scala。这是我 运行 遇到的问题:
我定义了一个特征,Generic
,带有一些容器类型的参数:
trait Generic[G[_]] {
// Some function declarations go here
}
现在我有一个抽象 class、Collect
,具有三个类型参数和一个函数声明(它表示一个类型,可以将类型 B
的所有子值收集到一个F[_]
类型的容器,来自 A
类型的某些结构):
abstract class Collect[F[_],B,A] {
def collect_ : A => F[B]
}
为了使其扩展Generic,给出了前两个类型参数F[_]
和B
,并柯里化了A
(这个效果是使用type lambdas模拟的):
class CollectC[F[_],B] extends Generic[({type C[A] = Collect[F,B,A]})#C] {
// Function definitions go here
}
问题是我需要隐式的最后一个 class 定义,因为稍后在我的代码中我需要能够编写像
这样的函数class GUnit[G[_]](implicit gg: Generic[G]) {
// Some definitions
}
当我简单地将 implicit
添加到 class 定义之前时,我得到一个错误 implicit classes must accept exactly one primary constructor parameter
。有没有人遇到过类似的问题?有没有一种已知的方法来解决它?我目前不知道如何在保持相同功能的同时重构我的代码,因此欢迎任何建议。提前致谢!
隐式 类 不会那样工作。它们是隐式 转换 的 shorthand。例如 implicit class Foo(i: Int)
等于 class Foo(i: Int); implicit def Foo(i: Int) = new Foo(i)
。所以它只适用于 类 ,它们的构造函数中只有一个参数。对于大多数 0 参数 (type-)类.
你的问题的标题似乎也暗示你认为编译错误是在谈论类型构造函数的类型参数,但我希望上面的段落也说明它实际上是在谈论 value 构造函数的 value 参数。
对于(我认为)您正在尝试做的事情,您必须自己提供 CollectC
的隐式实例。我建议将它放在 Collect
的同伴 object 中。但如果更符合您的需要,您可以选择 alternative solution。
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