【问题标题】:Scala weird type when coercing parameterize method into a function?将参数化方法强制转换为函数时的Scala奇怪类型?
【发布时间】:2020-07-06 12:33:09
【问题描述】:

无法读取 REPL 返回的以下类型

def  returnfuncdefGen[A] = (i: A) => i.toString.length

returnfuncdefGen: [A]=> A => Int

虽然我明白

def  returnfuncdefGen[A](i: A) = i.toString.length

returnfuncdefGen: [A](i: A)Int

第一个版本是FP简化(scala)的作者调用coercing parameterize method into a function

究竟如何阅读这个[A]=> A => Int

我也觉得强制的概念有点奇怪。在我看来,这就像创建一个返回函数的无括号方法。现在,上面的泛型我无法通过说字面函数执行方法定义的类型的闭包来解释其他。

总的来说,如果有人可以向我澄清正在发生的事情以及如何阅读那种真正有帮助的 [A]=> A => Int

【问题讨论】:

  • 我不认为这是强制。它只是一个返回函数的方法
  • 我猜这个问题是指这个页面alvinalexander.com/scala/fp-book-diffs-val-def-scala-functions(“将参数化方法强制转换为函数”部分)
  • 我猜在 Scala 语言规范中没有“强制”的概念(尽管在 Haskell 中有强制)。 def returnfuncdefGen[A](i: A) = i.toString.lengthdef returnfuncdefGen[A] = (i: A) => i.toString.length 的转换类似于 η-reduction en.wikipedia.org/wiki/Lambda_calculus#%CE%B7-reduction
  • 胖箭头是右关联的(我认为),所以你可以想象 A => Int 周围的括号。此外,向第一个方法添加一个空参数列表可能会对您有所帮助
  • 我想我明白你的意思了。你希望它是 [A](A) => Int?

标签: scala methods


【解决方案1】:

在 Scala 2.13.1 之前,我相信符号差异是按照 SLS 3.3.1 Method Types 设计的

方法类型在内部表示为 (Ps)? ... 一个特殊情况是 没有任何参数的方法类型。它们写在这里 => T。

因为方法returnfuncdefGen没有任何参数,所以它的类型用=> T表示法表示

scala> def  returnfuncdefGen[A] = (i: A) => i.toString.length
def returnfuncdefGen[A] => A => Int

在哪里T = A => Int

请参阅 Dmytro 对11416 MethodType.toString prints in scala format #7798 Scala 2.13.2 更改的回答

【讨论】:

  • 酷。 2.13.2 中更改了源,但规范没有。请参阅我的答案中的详细信息。
  • @DmytroMitin Dotty 似乎仍然以旧方式打印。
【解决方案2】:

如果你这样做

object App {
  def returnfuncdefGen[A] = (i: A) => i.toString.length
  def returnfuncdefGen1[A]() = (i: A) => i.toString.length
  def returnfuncdefGen2[A](i: A) = i.toString.length
}

def printSignature(name: String): Unit = {
  import scala.reflect.runtime.universe._
  val t = typeOf[App.type].decl(TermName(name)).typeSignature
  println(s"t=$t, showRaw(t)=${showRaw(t)}")
}

printSignature("returnfuncdefGen")
printSignature("returnfuncdefGen1")
printSignature("returnfuncdefGen2")

你会看到

t=[A]=> A => Int, showRaw(t)=PolyType(List(TypeName("A")), NullaryMethodType(TypeRef(ThisType(scala), scala.Function1, List(TypeRef(NoPrefix, TypeName("A"), List()), TypeRef(ThisType(scala), scala.Int, List())))))
t=[A]()A => Int, showRaw(t)=PolyType(List(TypeName("A")), MethodType(List(), TypeRef(ThisType(scala), scala.Function1, List(TypeRef(NoPrefix, TypeName("A"), List()), TypeRef(ThisType(scala), scala.Int, List())))))
t=[A](i: A)Int, showRaw(t)=PolyType(List(TypeName("A")), MethodType(List(TermName("i")), TypeRef(ThisType(scala), scala.Int, List())))

这是因为 NullaryMethodType toString 被定义为 =>

override def safeToString: String = "=> "+ resultType

也许您希望将其定义为 "",但直到 2.13.1(包括)才出现这种情况。

在 2.13.2 中为 NullaryMethodType toString 更改为 ""

override def safeToString: String = resultType.toString

https://github.com/scala/scala/blob/2.13.x/src/reflect/scala/reflect/internal/Types.scala#L2953

所以现在在 2.13.2、2.13.3 上面的代码打印出来了

t=[A]A => Int, showRaw(t)=PolyType(List(TypeName("A")), NullaryMethodType(TypeRef(ThisType(scala), scala.Function1, List(TypeRef(NoPrefix, TypeName("A"), List()), TypeRef(ThisType(scala), scala.Int, List())))))
t=[A](): A => Int, showRaw(t)=PolyType(List(TypeName("A")), MethodType(List(), TypeRef(ThisType(scala), scala.Function1, List(TypeRef(NoPrefix, TypeName("A"), List()), TypeRef(ThisType(scala), scala.Int, List())))))
t=[A](i: A): Int, showRaw(t)=PolyType(List(TypeName("A")), MethodType(List(TermName("i")), TypeRef(ThisType(scala), scala.Int, List())))

如你所愿。

顺便说一句,在 Dotty 0.26.0-bin-20200703-2dd1c93-NIGHTLY

def returnfuncdefGen[A] = (i: A) => i.toString.length
def returnfuncdefGen1[A]() = (i: A) => i.toString.length
def returnfuncdefGen2[A](i: A) = i.toString.length
def returnfuncdefGen3 = [A] => (i: A) => i.toString.length
def returnfuncdefGen4() = [A] => (i: A) => i.toString.length

>....def returnfuncdefGen[A] => A => Int
>....def returnfuncdefGen1[A](): A => Int
>....def returnfuncdefGen2[A](i: A): Int
>....def returnfuncdefGen3: PolyFunction{apply: [A](i: A): Int}
>....def returnfuncdefGen4(): PolyFunction{apply: [A](i: A): Int}

【讨论】:

    【解决方案3】:

    [A] => A => Int 是一个类型参数为 A 且没有参数的函数,它返回一个函数 `A => Int

    这与def returnfuncdefGen[A](i: A) = i.toString.length 不同,后者是一个类型参数为A 和一个A 类型的单个参数返回Int 的函数

    【讨论】:

    • 取你的第一段就意味着发生了强制? Def被强制转换为函数?否则为什么不是 a 类型的方法,没有返回函数的参数?
    • 这很奇怪,因为def returnfuncdef = (i: Int) => i + 2 不强制任何东西?可以 ?这里的类型是 Int => Int。对我来说,这是一种没有括号并返回函数的方法。
    • "[A] => A => Int 是一个函数...", "def returnfuncdefGen[A](i: A) = i.toString.length 这是一个函数..." 更准确地说,不是一个函数但方法。
    • 两者都不是函数,都是方法。但是第一个方法返回一个函数。函数和方法的区别很重要,特别是对于新手来说。有关差异的详细说明,请参阅this
    • @LuisMiguelMejíaSuárez 是的,完全同意,唯一的问题是符号。通常方法不使用箭头作为其返回类型。但在这种情况下确实如此。返回的函数是A => Int,但是你有[A] => A => Int,换句话说,``[A] => ``` 是关于方法的,这就是我的问题所在。我同意,我只是认为符号是错误的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-14
    • 2015-12-14
    • 1970-01-01
    • 2019-05-07
    • 2021-04-20
    • 1970-01-01
    相关资源
    最近更新 更多