Scala:隐式类

时间:2017-01-05 13:11:23

标签: scala implicit generic-programming

我试图将Haskell库的部分数据类型通用编程移植到Scala。这就是我遇到的问题:

我已经使用一些容器类型参数定义了一个特征Generic

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

现在我有一个抽象类Collect,它有三个类型参数和一个函数声明(它表示一种类型,而不是将B类型的所有子值收集到{{1}类型的容器中来自F[_]类型的某些结构:

A

为了使它扩展Generic,给出了前两个类型参数abstract class Collect[F[_],B,A] { def collect_ : A => F[B] } F[_],并且B是curry(使用lambdas类型模拟此效果):

A

问题是我需要隐含最后一个类定义,因为稍后在我的代码中我需要能够编写像

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

当我简单地将class GUnit[G[_]](implicit gg: Generic[G]) { // Some definitions } 添加到类定义中时,我收到错误implicit。有谁遇到过类似的问题?有没有一种已知的解决方法?我目前还没有看到如何在保持相同功能的同时重构代码,因此欢迎任何建议。提前谢谢!

1 个答案:

答案 0 :(得分:5)

隐性课程不会那样工作。它们是隐式转换的简写。例如,implicit class Foo(i: Int)等于class Foo(i: Int); implicit def Foo(i: Int) = new Foo(i)。所以它只适用于在构造函数中只有一个参数的类。对于大多数0参数(类型)类来说没有意义。

您的问题的标题似乎也暗示您认为编译错误是在讨论类型构造函数的类型参数,但我希望上面的段落也说明它实际上是在讨论 value 构造函数的参数。

对于你想要做的事情(我认为),你必须自己提供CollectC的隐式实例。我建议把它放在Collect的伴侣对象中。但如果能更好地满足您的需求,您可以选择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