def foo [A,B]究竟是什么意思?键入阴影

时间:2015-02-22 12:57:05

标签: 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练习之一)

附录

在阅读答案后,我添加了一些背景信息,以帮助未来的读者。该函数在特征中定义:

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

因此错误是由类型阴影引起的,但请参阅@ acjay下面的优秀答案。

Google搜索scala type shadowing并未导致任何scala文档中的直接定义,这很有趣,因为正如@travisbrown所说,它是最常见的一种我已经看到的初学者混乱的来源"。这里有一个讨论:Why does Scala support shadow variables?

1 个答案:

答案 0 :(得分:4)

在第一个例子中,只有一个类型参数,因为它不是一个独立的函数,它是类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是第二个元素的类型

键入Function1[A, B](更好地称为A => B) - A是参数类型,B是返回类型

......等等。