【问题标题】:Scala Pattern type is incompatible with expected typeScala Pattern 类型与预期类型不兼容
【发布时间】:2019-06-29 01:11:37
【问题描述】:

这是Why can't I run such scala code? (reduceRight List class method)的续集

我正在按照那里接受的答案重命名我的抽象类并添加 list: List[T] 作为方法 foldRight 的参数。

abstract class ListT {
    def foldRight[U](z : U)(list: List[T], op: (T, U) => U): U = list match {
        case Nil => z
        case x :: xs => op(x, foldRight(z)(xs, op))
    }
}

但我仍然收到“def”行的错误

此行有多个标记,未找到:键入 T

【问题讨论】:

  • 也许你想要List[T]
  • @LuisMiguelMejíaSuárez 抽象类 List[T]?不~这正是我引用的reduceRight方法线程的答案。
  • 那你需要在某处定义类型参数T。无论如何,让该方法接收另一个 List 有点奇怪。特别是因为那是标准库中的列表......你到底想做什么?使用 foldRight 方法定义您自己的 List 类?还是你自己的 foldRight 函数?
  • "。我不在乎它是在 stdlib List[T] 上运行还是在自定义抽象类上运行。"如果您希望模式匹配起作用,您将需要知道您操作的列表类型。 Nil:: 来自标准库。
  • 从头开始:是的。但更多的是通过定义MyList[T]MyNilmyConcat。您并不真正关心 T 是什么(假设您的列表可以使用任何类型的元素)。

标签: scala


【解决方案1】:

让我们从头开始,这应该可以帮助您掌握概念。

我们将创建自己的简单函数式列表
它将被称为MyList,将有一个名为MyNil 的空列表,并且cons 类/运算符为:!:

// Here we create the type MyList.
// The sealed is used to signal that the only valid implementations
//   will be part of this file. This is because, a List is an ADT.
// The A (which could be a T or whatever) is just a type parameter
//   it means that our list can work with any arbitrary type (like Int, String or My Class)
//   and we just give it a name, in order to be able to refer to it in the code.
// Finally, the plus (+) sign, tells the compiler that MyList is covariant in A.
//    That means: If A <: B Then MyList[A] <: MyList[B]
//    (<: means subtype of)
sealed trait MyList[+A] {
  def head: A // Here we say that the head of a List of As is an A.
  def tail: MyList[A] // As well, a tail of a List of As is another list of As.

  // Here we define the cons operator, to prepend elements to the list.
  // You can see that it will just create a new cons class with the new element as the head & this as the tail.
  // Now, you may be wondering why we added a new type B and why it must be a super type of A
  // You can check out this answer of mine:
  // https://stackoverflow.com/questions/54163830/implementing-a-method-inside-a-scala-parameterized-class-with-a-covariant-type/54164135#54164135
  final def :!:[B >: A](elem: B): MyList[B] =
    new :!:(elem, this)

  // Finally, foldRigh!
  // You can see that we added a new type parameter B.
  // In this case, it does not have any restriction because the way fold works.
  final def foldRight[B](z: B)(op: (A, B) => B): B = this match {
    case MyNil   => z
    case h :!: t =>  op(h, t.foldRight(z)(op))
  }
}

object MyList {
  // Factory.
  def apply[A](elems: A*): MyList[A] =
    if (elems.nonEmpty) {
      elems.head :!: MyList(elems.tail : _*)
    } else {
      MyNil
    }
}

// Implementations of the MyList trait.
final case class :!:[+A](head: A, tail: MyList[A]) extends MyList[A]
final case object MyNil extends MyList[Nothing] {
  override def head = throw new NoSuchElementException("head of empty list")
  override def tail = throw new NoSuchElementException("tail of empty list")
}

现在你可以:

val l1 = MyList(2, 3, 4) // l1: MyList[Int] = 2 :!: 3 :!: 4 :!: MyNil
val l2 = 1 :!: l1 // // l2: MyList[Int] = 1 :!: 2 :!: 3 :!: 4 :!: MyNil
val sum = l2.foldRight(0)(_ + _) // sum: Int = 10

【讨论】:

  • 多么详细的解决方案和解释!从头开始一切都清楚地说明了相关类型和方法是如何在 stdlib 中定义的。非常感谢路易斯!
猜你喜欢
  • 1970-01-01
  • 2018-08-07
  • 1970-01-01
  • 1970-01-01
  • 2023-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多