在Scala中创建自己的列表副本

时间:2016-12-22 08:09:39

标签: scala

我正在阅读Manning的Scala功能编程,由Paul Chiusano和Runar Bjarnason撰写。在第3章中,有一个用于创建List的代码,并且有用于实现列表的各种方法的赋值。以下是我的List

的部分实现
package src.Cons

sealed trait List[+A]
case object Nil extends List[Nothing]
case class Cons[+A](h:A, t:List[A]) extends List[A]

object List {

//my issue is I do not want to pass a list to sum but want to use objectName.sum notation
      def sum(ints:List[Int]):Int = ints match {
        case Nil => 0
        case Cons(x,xs) => x+sum(xs)
      }
    }

问题 - 如何创建列表,以便我可以拨打l.sum而不是List.sum(l)

4 个答案:

答案 0 :(得分:3)

您可以" PmL",正如@Gabriele Petronella建议的那样,或者您可以将sum()方法移动到Cons类,如@DeadNight所写,但在之前这些可以解决您List对象与List特征之间当前的冲突。

sum()对象中的List只能加List[Int],但您的类定义使用更通用的类型成员,因此您无法使用{{ 1}}因为编译器不知道如何添加两个+类型。

如果您想将A限制为仅处理数字类型,那么这将有效。

List

答案 1 :(得分:3)

使sum成员

问题是,您不知道如何对每种类型List[A] A求助,只有List[Int]。如果在AInt ...

时有办法允许通话

让我们来看看标准库。我们对Option#flatten method感兴趣,因为:

val o1 = Option(Option(3)).flatten // compiles
val o2 = Option(4).flatten // does not compile

注意奇怪的implicit ev: <:<[A, Option[B]]。这是关键 - 它是编译器为您提供的东西,但只有在编译时知道,Option[A]是某种类型Option[Option[B]]的子类型B }}。这是我们可以使用的技巧。

sealed trait List[+A] {
  def sum(implicit ev: A <:< Int): Int = this match {
    case Nil => 0
    case Cons(x, xs) => x + xs.sum // <- here x is magically converted to Int, so we can use plus
  }
}
case object Nil extends List[Nothing]
case class Cons[+A](h:A, t:List[A]) extends List[A]

println(Cons(4, Cons(38, Nil)).sum) // 42

ScalaFiddle

请注意,您可以将<:<[A, B]写为A <:< B

注意:还有=:=[A, B]类型,因为当您A正好Int时 - 您可以使用其中任何一种

做得更好?

实际上,std库有sum方法,它的类型甚至更奇怪: def sum(implicit ev: Numeric[A])。这样做允许它处理任何类似数字的类型,如DoubleInt,并具有比较,减法,乘法等操作。因此,您可以使它更通用。我建议你在阅读了关于Monoids的章节之后再这样做了。)

答案 2 :(得分:1)

您可以使用所谓的"Pimp my Library"模式。

定义隐式类ListOps

implicit class ListOps[+A](list: List[A]) {
  def sum = List.sum(this)
}

现在您可以致电list.sum。隐式转换将被触发,编译器将其解释为ListOps(list).sum

答案 3 :(得分:0)

在List trait

的定义中移动sum的定义

您可以将具体定义留给Nil&amp;缺点

package src.Cons

sealed trait List[+A] {
  def sum: Int
}

case object Nil extends List[Nothing] {
  val sum: Int = 0
}

case class Cons[+A](h:A, t:List[A]) extends List[A] {
  def sum: Int = h + t.sum
}