为什么绑定在高阶函数中的类型参数未正确应用?

时间:2019-05-07 16:35:43

标签: scala higher-order-functions

我试图实现一个函数,该函数需要另一个函数并将其应用到传递的列表上,而不是前一次调用的结果等等。 我想出了两个不同的函数签名,但是对于这两个编译器,它们都没有像我期望的那样派生类型参数,我现在想知道我是在搞砸事情还是在编译器。

object Repeater {
  // The first parameter is passed in a separate parameter list.
  def repeat[DstType >: ElemType, ElemType](list: List[ElemType])
                                           (function: DstType => DstType,
                                            times: Int): List[DstType] = {
    var currentList: List[DstType] = list
    for (_ <- 0 until times) {
      currentList = currentList.map(function)
    }
    currentList
  }

  // The first parameter is passed in the same parameter list as the others.
  def repeat2[DstType >: ElemType, ElemType](list: List[ElemType],
                                             function: DstType => DstType,
                                             times: Int): List[DstType] = {
    var currentList: List[DstType] = list
    for (_ <- 0 until times) {
      currentList = currentList.map(function)
    }
    currentList
  }
}

class Base()

class Extended() extends Base

object Test extends App {
  val list: List[Extended] = Nil

  Repeater.repeat(list)( x => x, 1)
  Repeater.repeat(list)( (x: Base) => x, 1)

  Repeater.repeat2(list, x => x, 1)
  Repeater.repeat2(list, (x: Base) => x, 1)
}

repeat()的第一次调用会编译,我不需要在给repeat()的函数中提供参数类型,这是我的预期行为。

repeat()的第二次调用无法编译:

Error:(25, 39) type mismatch;
 found   : pipeops.Base
 required: pipeops.Extended
  Repeater.repeat(list)( (x: Base) => x, 1)

我不理解此错误,因为找到的类型baseExtended的超级类型,因此适合我的提供类型绑定的DstType >: ElemTyp

repeat2()的第一次调用无法编译:

Error:(27, 26) missing parameter type
  Repeater.repeat2(list, x => x, 1)

我发现在这种情况下编译器希望我指定功能参数类型真的很奇怪。

repeat2()的第二次调用确实已编译并且是有意的。

我现在有两个问题:

  1. 有人可以向我解释这些差异来自何处吗?

  2. 是否存在另一种指定重复函数的方法,如果所传递的函数从ElemTypeElemType,则不需要我指定参数类型,但允许我扩展所传递的函数如果需要,函数类型可用于ElemType的超级类型。

1 个答案:

答案 0 :(得分:1)

一种类型参数有什么问题?

  object Repeater {
    def repeat[ElemType](list: List[ElemType])
                                             (function: ElemType => ElemType,
                                              times: Int): List[ElemType] = {
      var currentList: List[ElemType] = list
      for (_ <- 0 until times) {
        currentList = currentList.map(function)
      }
      currentList
    }

    def repeat2[ElemType](list: List[ElemType],
                                               function: ElemType => ElemType,
                                               times: Int): List[ElemType] = {
      var currentList: List[ElemType] = list
      for (_ <- 0 until times) {
        currentList = currentList.map(function)
      }
      currentList
    }
  }

  class Base()

  class Extended() extends Base

  object Test extends App {
    val list: List[Extended] = Nil
    val list1: List[Base] = list

    Repeater.repeat(list)( (x: Extended) => x, 1)
    Repeater.repeat(list1)( (x: Base) => x, 1)

    Repeater.repeat2(list, (x: Extended) => x, 1)
    Repeater.repeat2(list, (x: Base) => x, 1)
    Repeater.repeat2(list1, (x: Base) => x, 1)

    Repeater.repeat[Extended](list)( (x: Extended) => x, 1)
    Repeater.repeat[Base](list1)( (x: Base) => x, 1)
    Repeater.repeat2[Extended](list, (x: Extended) => x, 1)
    Repeater.repeat2[Base](list, (x: Base) => x, 1)
  }

如果有时候编译器没有让您明确指定类型,则意味着它可以自己推断类型,否则就不能,您应该指定。