【问题标题】:Difference between * (star) and _ (underscore) in type parameter类型参数中 *(星号)和 _(下划线)之间的区别
【发布时间】:2020-08-24 10:09:33
【问题描述】:

Here 有人说星号是 scala 3 的下划线,但我在 scala 2.13 中看到过这样的代码:

def make[F[_]: ContextShift: MonadError[*[_], Throwable]: Effect: Logging](): ...

它的含义相同,只是指定 * 中的类型与 _ 中的类型不同吗?

【问题讨论】:

  • *[_] 来自 kind-projector 插件。

标签: scala functional-programming scala-cats kind-projector


【解决方案1】:

_ 表示(取决于上下文)

  • 类型构造函数 - 如果用作类型参数定义/约束
    def foo[F[_]]: Unit
    
  • 存在类型 - 如果应用于应该用作正确类型的东西
    def bar(f: F[_]): F[_]
    

这里我们要了解类型构造函数。

类型构造函数将是(简化)F 的东西,还没有定义那个东西,但我们可以将A 应用于它并使其成为F[A]。例如

  • List 可以作为 F[_] 传递,因为它有一个间隙,如果我们用例如填充它。 String 可以变成List[String]
  • Option 也可以作为F[_] 传递,如果我们用例如填充它,它会有一个空白。 Int 会变成 Option[Int]
  • Double 不能用作F[_],因为它没有间隙

带有“间隙”的类型通常表示为* -> *,而没有间隙的类型通常表示为*。我们可以将* 简单地理解为一种类型,而将* -> * 理解为“采用另一种类型形成类型的类型”——或类型构造函数。

(像刚才提到的那种高级类型本身就是复杂的东西,所以你最好在这个问题之外更多地了解它们。

*(来自kind projector plugin)用于种类投影——语法的灵感来自上面的符号,以显示如果我们想创建一个新类型,类型将被传递到哪里:

Monad[F[List[*]]]

真的很像:

type UsefulAlias[A] = F[List[A]]
Monad[UsefulAlias]

除了它在没有类型别名的情况下工作。

如果是 Dotty,最好用 type lambda 表示:

// Monad[F[List[*]]] is equal to
[A] =>> Monad[List[A]]

在你的例子中:

def make[F[_]: ContextShift: MonadError[*[_], Throwable]: Effect: Logging](): ...
  • F[_] 被定义为类型构造函数 - 所以你不能通过 StringIntByte,但你可以在那里通过 ListFutureOption(因为它们采用一个类型参数)
  • F[_]: ContextShift[F[_]](implicit sth: ContextShift[F]) 的快捷方式 - 我们可以看到 ContextShift 将某些东西作为参数,该参数本身带有类型参数(如 F[_]
  • [F[_]: MonadError[*[_], Throwable] 可以扩展为:
    type Helper[G[_]] = MonadError[G, Throwable]
    [F[_]: Helper]
    
    反过来可以重写为
    type Helper[G[_]] = MonadError[G, Throwable]
    [F[_]](implicit me: Helper[F])
    
    或使用类型 lambda
    [F[_]] =>> MonadError[F, Throwable]
    

如果写成这样可能会更容易阅读:

def make[F[_]: ContextShift: MonadError[*, Throwable]: Effect: Logging]():

问题是,* 会暗示预期的类型是

[A] =>> MonadError[A, Throwable]

同时* 的善意应该是* -> * 而不是*。所以这个*[_] 的意思是“我们想在这里创建一个新的类型构造函数,用这个东西代替* 一个参数,但我们想表示这个参数是* -> *而不是*

[F[_]] =>> MonadError[F, Throwable]

所以我们将添加[_] 以向编译器显示它是一个类型构造函数。

吸收的比较多,应该会比较容易,只能不好意思说,在Dotty里会更清晰。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-19
    • 2014-08-27
    • 1970-01-01
    • 2010-10-10
    • 2022-11-13
    • 2013-11-17
    • 2019-07-21
    • 2012-12-09
    相关资源
    最近更新 更多