【问题标题】:Defining a constructor for a typeclass that takes a method with a type parameter?为接受带有类型参数的方法的类型类定义构造函数?
【发布时间】:2021-02-14 17:09:08
【问题描述】:

我有一种情况,我所知道的解决方案都不是好的解决方案。我正在尝试定义一个类型类,如下例所示,它有一个抽象类型S,它必须实现另一个类型类(未显示)Valid[A]。感觉最简单的方法是创建一个apply 构造函数,这将强制用户输入S 并自动为sIsValid 引入一个隐式实例。

这个问题是函数changeType 需要一个类型参数。尽管进行了一些谷歌搜索,但我还没有弄清楚如何为接受类型参数的函数编写类型注释(这可能是因为 Scala 似乎不允许带有类型参数的匿名函数)。我的方法在这里看起来是否明智?如果我可以为changeType 提供类型注释,那么类型类用户仍然可以将非匿名函数传递给apply 构造函数,这似乎是一个最令人满意的解决方案。

abstract class IsTC[A[_], T] {
  // type S is an abstract type rather than type parameter, but must implement Valid[A]
  type S
  implicit val sIsValid: Valid[S]

  def get(self: A[T], i: Int): T
  def changeType[_T]: A[_T]
}
object IsTC {
  def apply[A[_], T, _S](
    fget: (A[T], Int) => T,
    fchangeType:  // what should this type annotation be?
  ): IsTC[A, T] { type S = _S } = new IsTC[A, T] {
    type S = _S
    def get(self: A[T], i: Int) = fget(self, i)
    def changeType[_T]: A[_T] = fchangeType[_T]
  }
}

感激地收到任何帮助/想法。

【问题讨论】:

  • 其实我猜你已经问过类似的问题stackoverflow.com/questions/64130596/…
  • @DmytroMitin - 感谢下面的回答 - 我现在正在工作,但今晚会试一试。是的,这个问题是相似的,尽管不完全相同。在过去的几个月里,我想我已经发布了至少十个关于这个和密切相关的主题的问题,其中绝大多数问题你都已经很好地回应了。我一直在使用大量的试验和错误来弄清楚什么是实际可能的,然后什么对图书馆用户来说是符合人体工程学的。
  • 是的,我知道大约十个问题,没关系,我只是提到你已经问过构造方法(instance 那里,apply 这里)对于具有多态的类型类方法(get[R] 那里,changeType[_T] 这里)和多态函数类型([A] => (A, R) => O 那里,[X] => A[X] 这里)。
  • @DmytroMitin - 是的 - 在我看来,这个问题与另一个问题不同。实际上,它可能不是……

标签: scala typeclass polymorphic-functions


【解决方案1】:

Scala 2 不支持多态函数。多态可以是方法,而不是值。和函数are 值。多态函数可以用包装器模拟

// for [A] => (a: A) => B[A]
trait Poly {
  def apply[A](a: A): B[A]
}

// for [A <: U] => (a: A) => B[A]
trait Poly[U] {
  def apply[A <: U](a: A): B[A]
}

喜欢shapeless.Poly。他们概括了普通函数

trait Function[A, B] {
  def apply(a: A): B
}

试试

object IsTC {
  def apply[A[_], T, _S](
                          fget: (A[T], Int) => T,
                          fchangeType: FchangeType[A]
                        ): IsTC[A, T] { type S = _S } = new IsTC[A, T] {
    override type S = _S
    override implicit val sIsValid: Valid[_S] = ???
    override def get(self: A[T], i: Int) = fget(self, i)
    override def changeType[_T]: A[_T] = fchangeType[_T]
  }
}

trait FchangeType[A[_]] {
  def apply[X]: A[X]
}

Dotty has 多态函数 [A &lt;: U] =&gt; (a: A) =&gt; f[A](a) 的多态函数类型 [A &lt;: U] =&gt; A =&gt; B[A] 但是有 implementation restriction: polymorphic function types must have a value parameter 所以你不能有多态函数类型 [X] =&gt; A[X] (not to be confused 与类型 lambda [X] =&gt;&gt; A[X])甚至在那里。

此外(除了使用包装器进行模拟之外)一些多态类型可以通过存在类型表示:[A] =&gt; B[A] =&gt; C(对于常量C)实际上是B[_] =&gt; C

这是因为∀a: (B(a) =&gt; C)(∃a: B(a)) =&gt; C

【讨论】:

  • 谢谢,这确实有效,但感觉有点尴尬。事实上,我正在尝试做该语言并不真正支持的事情,这让我觉得我可能在设计过程的早期做出了错误的选择。
  • @Chrisper 是的,正如我在那个问题中所写,由于类型类具有多态方法,很可能您不需要构造函数方法(instance/apply),您可以创建实例通过new ...
猜你喜欢
  • 2015-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-25
  • 2020-07-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多