1

这是我的 scala2 代码到 scala3 的直接翻译

trait Narrow[F[_], A, B <: A: ClassTag]:
  def apply(fa: F[A]): F[B]

extension [F[_], A] (fa: F[A]):
  def narrow[B: ClassTag] (using op: Narrow[F, A, B]): F[B] = op(fa)

我需要在调用站点指定窄操作的类型,但是扩展方法不允许该语法。这个限制有什么最好的解决方法?

这样做的目的是能够缩小集合/尝试/任何东西中的类型。窄类型类将对内部的任何内容进行平面映射,比较运行时类型,如果它匹配将 B 包装在 F 中,或者返回一个空 F

trait A
trait B extends A
object A extends A
object B extends B

val bb: List[B] = List(A, A, B, B, A)
  .narrow[B]
assert(bb == List(B, B))
4

2 回答 2

1

如果你能处理丑陋,你可以使用多态函数:

extension [F[_], A] (fa: F[A]):
  def narrow() = [B <: A] => (using op: Narrow[F, A, B]) => op(fa)

然后,您可以使用foo.narrow()[String]. 是在斯卡斯蒂。

narrow()是必要的,因为没有它,类型参数将转到扩展而不是多态函数。

将来,Scala 3 可能允许将类型参数直接传递给扩展中的方法,但现在,您可以继续使用 Scala 2 隐式类并在下一个版本后更改它:

implicit class NarrowOps[F[_], A](fa: F[A]):
  def narrow[B <: A](using op: Narrow[F, A, B]) = op(fa)

斯卡斯蒂

旁注:你不需要B: ClassTag在你的扩展中再次使用,尽管我相信你确实需要使用 bound B <: A

于 2020-12-04T00:28:45.493 回答
1

我无法忍受()呼叫站点上的。我决定尝试使用仅带有类型参数的 apply 方法隐式转换为类型。

trait NarrowTypeClass[F[_], A, B <: A: ClassTag]:
  def apply(fa: F[A]): F[B]

given [F[_], A] as Conversion[F[A], Narrowable[F, A]] = Narrowable(_)

sealed class Narrowable [F[_], A] (fa: F[A]):
  def narrow[B <: A: ClassTag] (using op: NarrowTypeClass[F, A, B]): F[B] = op(fa)

这似乎可以解决问题

于 2020-12-04T15:49:41.300 回答