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

Scala def foo[A,B]到底是什么意思?类型阴影,scala,Scala,当我编写像def foo[a,B]这样的函数时,[a,B]到底是什么意思?我知道这是一场灾难;但是什么时候使用foo[A]和foo[A,B] 这里有一个例子,我不明白其中的区别。此函数编译: def map[B](f: A => B): Stream[B] = foldRight(empty[B])((h,t) => cons(f(h), t)) 而这个没有编译。我不明白为什么不需要A

当我编写像def foo[a,B]这样的函数时,[a,B]到底是什么意思?我知道这是一场灾难;但是什么时候使用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:

这是其中一个练习

附录

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

trait Stream[+A] { 
  ...
  def map[B](f: A => B):Stream[B] = 
    foldRight(empty[B])((h,t) => cons(f(h), t))
  ...
}
因此错误是由类型阴影造成的,但请参见下面@acjay的优秀答案


谷歌搜索scala类型的阴影在任何scala文档中都不会产生直接的定义,这很有趣,因为正如@travisbrown在下面所说的,这是我见过的初学者困惑的最常见来源之一。这里有一个讨论:

在第一个示例中,只有一个类型参数,因为它不是孤立的函数,而是类流[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.mapMystreamMappingFunction,而不是myStream.mapmyMappingFunction。这两个选项都非常有效,但将方法放入类中可能更为惯用

所以,为了回答您的问题,当两个或多个参数和/或返回类型需要为泛型时,可以对一个方法使用多个类型参数。您还可以为类使用两个类型参数,例如忽略方差:

类型映射[A,B]-A是键类型,B是值类型

类型Tuple2[A,B]通常被称为A,B-A是第一个元素的类型,B是第二个元素的类型

类型Function1[A,B]通常称为A=>B-A是参数类型,B是返回类型


…等等。

您在哪里看到map方法?如果它是一个类的成员,那么该类本身可能会定义一个类型参数,我假设您在定义流[a]的类中定义映射,因此,抽象类型A已经定义,map只需要为函数的结果类型提供一个抽象名称。这意味着您正在定义一个处理两种不同类型的函数,而您还不知道它们,因此您将给它们命名为A.B作为占位符。您告诉编译器,当用户调用函数时,它应该使用与函数使用位置相关的正确类型替换a和B。感谢@mucaho和@Freidereikhs,这确实是流特征的一部分,我将更新问题以添加一些上下文。非常感谢@acjay的出色回答,我现在明白了。我将为我的问题添加一个附录,以提供一些背景。
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))

  // ...
}