scala - def foo[A,B] 到底是什么意思?类型阴影

标签 scala

当我编写像 def foo[A,B] 这样的函数时,[A,B] 到底是什么意思?我知道这是一个Polymorphic Method ;但是什么时候使用 foo [A]foo [A,B] 呢?

这是一个我不明白其中区别的例子。该函数编译:

def map[B](f: A => B): Stream[B] =                                               
  foldRight(empty[B])((h,t) => cons(f(h), t))

然而这个不能编译。我不明白为什么不需要 A,毕竟 A 是由 f: A => B 引用的:

def map[A,B](f: A => B): Stream[B] =                                            
  foldRight(empty[B])((h,t) => cons(f(h), t))

[error] ..../Stream.scala:61: type mismatch;
[error]  found   : h.type (with underlying type A)
[error]  required: A
[error]     foldRight(empty[B])((h,t) => cons(f(h), t))

(这是来自 FP in Scala 练习之一)

附录

阅读答案后,我添加了一些上下文,以帮助 future 的读者。该函数在特征内定义:

trait Stream[+A] { 
  ...
  def map[B](f: A => B):Stream[B] = 
    foldRight(empty[B])((h,t) => cons(f(h), t))
  ...
}

所以错误是由类型阴影引起的,但请参阅下面 @acjay 的出色答案。

谷歌搜索 scala 类型遮蔽 不会在任何 scala 文档中产生直接定义,这很有趣,因为正如 @travisbrown 下面所说,它是“初学者困惑的最常见来源之一”我见过”。这里有一个讨论:Why does Scala support shadow variables?

最佳答案

在第一个示例中,只有一个类型参数,因为它不是一个孤立的函数,它是类 Stream[A] 中的一个方法,它声明了第一个类型参数。大概是这样的:

class Stream[A] {
  // ...

  def map[B](f: A => B): Stream[B] =                                               
    foldRight(empty[B])((h,t) => cons(f(h), t))

  // ...
}

因此,您可以从周围的类范围中获取A。假设您在伴生对象上创建了 map 方法。在这种情况下,伴生对象没有类型参数,因此您必须在方法上定义这两个参数:

class Stream[A] {
  // ... methods, with foldRight, but no `map`
}

object Stream {
  // ...

  def map[A, B](stream: Stream[A])(f: A => B): Stream[B] =                                               
    stream.foldRight(empty[B])((h,t) => cons(f(h), t))

  // ...
}

第二个选项的使用方式略有不同。您会说 Stream.map(myStream)(myMappingFunction) 而不是 myStream.map(myMappingFunction)。这两个选项都完全有效,但将方法放入类中可能更惯用。

因此,为了回答您的问题,当两个或多个参数和/或返回类型需要是泛型时,您可以在方法上使用多个类型参数。您还可以为类使用两个类型参数,例如(忽略方差):

类型 Map[A, B] - A 是键类型,B 是值类型

类型 Tuple2[A, B] (更广为人知的名称是 (A, B)) - A 是第一个元素的类型, B 是第二个元素的类型

Type Function1[A, B](更广为人知的是 A => B) - A 是参数类型, B 是返回类型

...等等。

关于scala - def foo[A,B] 到底是什么意思?类型阴影,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28658034/

相关文章:

mysql - Spark Mysql 快速更新

scala - 具有案例类的双向引用

scala - Scalding TypedPipe API 外部操作模式

scala - 从一个列表中提取不在另一个列表中的元素

Scala:带元组的 flatMap

scala - 如何在 build.sbt 中一次更改范围内的许多设置?

regex - scala 在捕获组上拆分

scala - 在 Haskell 中编写时间函数

Scala IDE 支持自动补全和语法高亮

带有下划线的scala传递函数产生一个函数而不是一个值