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



我有一个trait定义,当像这样实例化时包装副作用:

trait MyTrait[F[_]] {
def func1(param: Param): F[Param]
}

我的Param是一个case类,它本身接受这样的类型参数:

final case class Param[F[_]] {
field1: F[String],
field2: F[Int]
)

现在我的问题是,如果我将trait方法签名更改为以下内容,这意味着什么:

trait MyTrait[F[_]] {
def func1(param: Param[_]): F[Param[_]]
}

正如您所看到的,我在引用Param case类的任何地方都使用了通配符。这是一个好方法吗?我不想将我的接口绑定到方法参数上的类型期望。

正如@AndreyTyukin注意到的,你的代码无法编译,因为ParamF在种类上不一致

trait MyTrait[F[_]] {
def func1(param: Param): F[Param]
}
//compile error: class Param takes type parameters
final case class Param[F[_]](
field1: F[String],
field2: F[Int]
)

https://scastie.scala-lang.org/DmytroMitin/K2EHGDXERFCJisz45edMsA

也许你的意思是

trait MyTrait[F[_]] {
def func1(param: Param[F]): F[Param[F]]
}
final case class Param[F[_]](
field1: F[String],
field2: F[Int]
)

https://scastie.scala-lang.org/DmytroMitin/K2EHGDXERFCJisz45edMsA/1

func1返回类型F[Param[F]]看起来像固定点https://free.cofree.io/2017/11/13/recursion/

现在我的问题是,如果我将trait方法签名更改为以下内容,这意味着什么:

trait MyTrait[F[_]] {
def func1(param: Param[_]): F[Param[_]]
}

代替具有当前效果的Param[F]F,您开始使用具有任意(未知)效果的存在类型Param[_],可能与F不同。

什么是存在类型?

这是一个好方法吗?我不想将我的接口绑定到方法参数上的类型期望。

取决于你的目标。对于您的设置,MyTraitParam将具有不连接的效果,这有意义吗?

例如,其中一个正在写入数据库,而另一个正在写入磁盘上的文件。其中一个在进行时间旅行,而另一个在发射导弹。

如果您的设置确实有意义,可以使用不同的效果,请考虑修改签名,在方法级别上添加第二种效果类型(而不是存在)

trait MyTrait[F[_]] {
def func1[G[_]](param: Param[G]): F[Param[G]]
}

(还是应该是F[Param[F]]?)或者G[Param[F]]?这取决于你的设置)

或在类型-类级别

// (*)
trait MyTrait[F[_], G[_]] {
def func1(param: Param[G]): F[Param[G]]
}

或者你也可以试试

trait MyTrait[F[_]] {
def func1[G[_], H[_]](param: Param[G]): F[Param[H]]
}

trait MyTrait[F[_], G[_], H[_]] {
def func1(param: Param[G]): F[Param[H]]
}

在Scala的新问题类型参数和边界之后,我将在这里添加一个选项,即使G成为抽象类型成员而不是方法的类型参数。那么G必须在继承程序中实现,而不是方法必须为任意G工作。

trait MyTrait[F[_]] {
type G[_]
def func1(param: Param[G]): F[Param[G]]
}

它类似于上面的(*),即让G成为type-class的类型参数。

最新更新