【问题标题】:Does Scala support partial application of type constructors?Scala 是否支持类型构造函数的部分应用?
【发布时间】:2018-02-23 14:50:23
【问题描述】:

我正在向 scala-exercises 学习猫。
想知道如何使用高阶类型,有一些尝试:

 trait Functor[F[_]] {
   def map[A, B](fa: F[A])(f: A => B): F[B]
 }

 def someThingFail1[In]() = new Functor[Function1[In, _]] {
    override def map[A, B](fa: Function1[In, A])(f: A => B): Function1[In, B] = ???
  }

  def someThingFail2[In]() = new Functor[Either[In, _]] {
    override def map[A, B](fa: Either[In, A])(f: A => B): Either[In, B] = ???
  }

  def someThingFail3() = new Functor[List[_]] {
    override def map[A, B](fa: List[A])(f: A => B): List[B] = ???
  }

  //only this one can compile 
  def someThingRight1() = new Functor[List] {
    override def map[A, B](fa: List[A])(f: A => B): List[B] = ???
  }

前面三个函数不能编译,错误信息如下:

[error] /Users/lorancechen/version_control_project/_tutorials/learn-cats/src/main/scala/mycats/Main.scala:16:42: Either[In, _] takes no type parameters, expected: one
[error]   def someThingFail2[In]() = new Functor[Either[In, _]] {
[error]                                          ^

为什么 Scala 不支持类型孔? Dotty 编译器会支持它吗?谢谢

【问题讨论】:

    标签: scala scala-cats type-constructor


    【解决方案1】:

    那是因为

    Either[X, _]
    

    是一个存在类型,它可以显式写成

    Either[X, Y] forSome { type Y }
    

    这有点类似于 Java 的通配符,而不是您想要的更高阶 Functor 类型构造函数的参数。你想要的是一个 type lambda。原来可以这样写:

    ({type lam[Y] = Either[X, Y]})#lam
    

    类型 lambdas 可以在 Scala 中使用这一事实根本不是计划中的功能,而是accidental discovery,而且语法有点冗长。但是,有一个 non/kind-projector 插件可以大大简化它。有了这个插件,你的代码就变成了:

    trait Functor[F[_]] {
      def map[A, B](fa: F[A])(f: A => B): F[B]
    }
    
    def someThingFail1[In]() = new Functor[Function1[In, ?]] {
      override def map[A, B](fa: Function1[In, A])(f: A => B): Function1[In, B] = ???
    }
    
    def someThingFail2[In]() = new Functor[Either[In, ?]] {
      override def map[A, B](fa: Either[In, A])(f: A => B): Either[In, B] = ???
    }
    
    def someThingFail3() = new Functor[List[?]] {
      override def map[A, B](fa: List[A])(f: A => B): List[B] = ???
    }
    
    //only this one can compile 
    def someThingRight1() = new Functor[List] {
      override def map[A, B](fa: List[A])(f: A => B): List[B] = ???
    }
    

    (使用 scala 2.12.4、cats 1.0.1、kind-projector 0.9.4 测试)。

    注意这个插件is used in cats source code(搜索?)。

    dotty 中的一切都会变得更好,它already supports a neat syntax for type lambdas

    【讨论】:

    • 谢谢,现在对我来说很清楚了。在 Dotty 中,语法已经足够好了,作为另一个例子,type A[+T] = List[T] 是否与 type A = List 相同?此外,Dotty 删除了存在类型,为什么不将 Either[Int, _] 作为类型 lambda 语法,这似乎很好写和理解。
    • 我猜你可以写type A = [X] => List[X],它在scala的2.12.x中肯定行不通。为什么他们不将存在类型的语法重用为类型 lambda?也许他们想保留稍后再次添加类似内容的可能性,也许他们只是不希望有人试图将带有存在的遗留 scala 代码编译为带有 lambdas 类型的 dotty 代码。我不知道。
    • @LoranceChen "此外,Dotty 删除了存在类型" 它删除了 forSome 的存在类型,通配符仍然存在。
    猜你喜欢
    • 1970-01-01
    • 2019-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多