部分应用类型参数

发布于 2024-10-29 19:36:33 字数 282 浏览 2 评论 0原文

我拼命地试图解决以下问题:

trait Access[Res[_]] { def access[C]: Res[C] }

trait CList[C1, A] extends Access[CList[_, A]] // ?!

def test[C1, C2, A](c: CList[C1, A]): CList[C2, A] = c.access[C2]

scalac 只是说:“错误:涉及特征 CList 的非法循环引用”。我怎样才能编译这个?

I'm desperately trying to solve the following:

trait Access[Res[_]] { def access[C]: Res[C] }

trait CList[C1, A] extends Access[CList[_, A]] // ?!

def test[C1, C2, A](c: CList[C1, A]): CList[C2, A] = c.access[C2]

scalac just says: "error: illegal cyclic reference involving trait CList". how can I make this compile?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

多孤肩上扛 2024-11-05 19:36:33

您可能对 lambda 类型感兴趣。您在答案中使用的部分应用程序实际上是 在 scalaz 中实现< /a>.
然而,由于代码的可读性往往较差,他们开始使用 lambda 类型。有问题的类型可以写为:

({type λ[α] = CList[α,A]})#λ

这通过在结构类型内部的参数化类型λ上创建类型投影来实现,从而捕获外部类型参数(在本例中为A) 。

您的答案中描述的有关方差的另一个问题可以通过将 Access 中的 Res 参数设置为协变来解决。

进行这些更改后,您的代码应如下所示:

trait Access[+Res[_]] { def access[C] : Res[C]}

trait CList[C, +A] extends Access[({type λ[α] = CList[α,A]})#λ]

You might be interested in type lambdas. The partial application you used in your answer is actually implemented in scalaz.
As the code tends to get less readable though, they started using type lambdas instead. The type in question could be written as

({type λ[α] = CList[α,A]})#λ

This works by creating a type projection on a parameterized type λ inside a structural type thus capturing the outer type parameter (in this case A).

The other problem concerning variance described in your answer could be solved by making the Res parameter in Access covariant.

After these changes your code should look like this:

trait Access[+Res[_]] { def access[C] : Res[C]}

trait CList[C, +A] extends Access[({type λ[α] = CList[α,A]})#λ]
只有影子陪我不离不弃 2024-11-05 19:36:33

只是为了更新一些东西
将此编译器插件添加到您的sbt中以进行种类投影,您将使用?获得一个不错的语法。
这删除了看起来很混乱的类型投影样板!
所以你可以编写类似 Either[String, ?]

addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.9.7 ")

它是使用下面相同的旧类型投影实现的

您还可以在这里找到它:
https://underscore.io/blog/posts/2016/12/05/type-lambdas.html

Just to update things
add this compiler plugin to your sbt for kind projection and you'll get a nice syntax using ?.
This removes the type projection boilerplate which looks messy!
So you can write stuff like Either[String, ?]

addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.9.7")

it's implemented with the same old type projection underneath

You can also find it here:
https://underscore.io/blog/posts/2016/12/05/type-lambdas.html

梦中楼上月下 2024-11-05 19:36:33

谷歌搜索“部分类型应用程序”,我发现 James Iry 在 scala 辩论列表上发布了这个解决方案( http://scala-programming-language.1934581.n4.nabble.com/Partial-type-in​​ference-td2007311.html ;进行了调整,以便更改参数顺序) :

type Partial2[T[_,_], B] = {
   type Apply[A] = T[A,B]
}
trait CList[C1, A] extends Access[Partial2[CList, A]#Apply]

cheese louise,这真的是 2011 年在 scala 中做到这一点的唯一方法吗?!!

编辑:

这会因A中的协方差而失败:,-(

trait Access[Res[_]] { def access[C]: Res[C] }

type Partial2[T[_,_], B] = {
  type Apply[A] = T[A,B]
}
trait CList[C1, +A] extends Access[Partial2[CList, A]#Apply]

"covariant type A occurs in invariant position"

googling for "partial type application" i found this solution posted by James Iry on the scala debate list ( http://scala-programming-language.1934581.n4.nabble.com/Partial-type-inference-td2007311.html ; adapted so the arg order is changed):

type Partial2[T[_,_], B] = {
   type Apply[A] = T[A,B]
}
trait CList[C1, A] extends Access[Partial2[CList, A]#Apply]

cheese louise, is this really the only way to do that in scala in 2011 ?!!

EDIT:

This fails with covariance in A :,-(

trait Access[Res[_]] { def access[C]: Res[C] }

type Partial2[T[_,_], B] = {
  type Apply[A] = T[A,B]
}
trait CList[C1, +A] extends Access[Partial2[CList, A]#Apply]

"covariant type A occurs in invariant position"
雨轻弹 2024-11-05 19:36:33

我知道这是一个非常老的问题,但无论如何:

trait AnyAccess {
  type Res[X]
  def access[Z]: Res[Z]
}

trait AnyCList extends AnyAccess { me =>
  type C
  type A
  // this could be a subtype bound instead, if needed
  type Res[X] = AnyCList { type C = X; type A = me.A }
}
case object AnyCList {
  type of[C0, +A0] = AnyCList { type C = C0; type A <: A0 }
}

case object buh {

  def test[C1, C2, A](c: AnyCList.of[C1, A]): AnyCList.of[C2, A] = c.access[C2]
}

I know this is a really old question, but anyway:

trait AnyAccess {
  type Res[X]
  def access[Z]: Res[Z]
}

trait AnyCList extends AnyAccess { me =>
  type C
  type A
  // this could be a subtype bound instead, if needed
  type Res[X] = AnyCList { type C = X; type A = me.A }
}
case object AnyCList {
  type of[C0, +A0] = AnyCList { type C = C0; type A <: A0 }
}

case object buh {

  def test[C1, C2, A](c: AnyCList.of[C1, A]): AnyCList.of[C2, A] = c.access[C2]
}
一曲琵琶半遮面シ 2024-11-05 19:36:33

这是一种对我“部分应用类型参数”有用的方法:

我有一个像这样的函数

def foo[A, B, C, D, E](...)

,我只需要提示一个类型参数,以便编译器推断其余的类型参数。这对我有用:

object InferType {
  type InferType[A] = Option[A]
  def apply[A]: Option[A] = None
}

更新 foo 以获取 InferType 类型的附加参数:

// t parameter is unused in implementation but
// is used by compiler to infer other type parameters
def foo[A, B, C, D, E](..., t: InferType[D]) 

用法:

foo(..., InferType[ConcreteD])

Here's a method that worked for me to "partially apply type parameters":

I had a function like

def foo[A, B, C, D, E](...)

Such that I needed to hint only one type parameter for the compiler to infer the rest. This worked for me:

object InferType {
  type InferType[A] = Option[A]
  def apply[A]: Option[A] = None
}

Update foo to take an additional parameter of type InferType:

// t parameter is unused in implementation but
// is used by compiler to infer other type parameters
def foo[A, B, C, D, E](..., t: InferType[D]) 

Usage:

foo(..., InferType[ConcreteD])
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文