Scala - implementing List

本文深入探讨了Scala中List类的原理、构造及高效操作方法,包括List类的基本概念、封装方式、实例创建、操作优化等核心内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


we will introduce the following topic based on the Implementing lists. they are

  1. List class principles.
  2. List constructions. 


List class principles

first, the abstract List class definition. 

package scala
abstract class List[T+] { // ... 
  
}
and by default, the provided two case classes that has two case class implementation. they are :: (yes, you are not mistaken, in scala you can use some identified that you believe is not a identifier)... and a Nil class. the hierarchy is as follow. 
// the class that we will examine is as follow.
//                    scala
//                 List[+T]
//             << sealed abstract>>
//                    ^
//                    |
//    +---------------+---------------------+
//    |                                     |
//  scala                                 scala
// ::[T]                                   Nil
//<<final case>>                      <<case object>>
List are covaraince, so that 
// List are covariance
val xs = List(1, 2, 3) // type of xs:List[Int]

var ys : List[Any] = xs // type List[Any]
and this is the implementation of the Nil object. 
// the nil object

case object Nil extends List[Nothing] {
  override def isEmpty = true
  def head : Nothing = throw new NoSuchElementException("head of empty list")
  def tail : Nothing = throw new NoSuchElementException("head of empty list")
}
since List is covaraince, so that means that Nil can be a subclass of other List objct.

then, let's check the :: class. 

// -- the :: class

final case class :: [T] (hd : T, tl: List[T]) extends List[T] {
  def head = hd
  def tail = tl
  override def isEmpty : Boolean = false
}
this can be simplified.
// it can be made simpler 
final case class :: [T] (head : T, tail: List[T]) extends List[T] {
  override def isEmpty : Boolean = false
}
the three methods that lay the basis of the all List operations are isEmpty, head, and tail.
//, isEmpty, head, and tail are the three operation that is the foundation to every other list operations
// e.g. 
def length : Int = if (isEmpty) 0 else 1 + tail + tail.length
def drop(n : Int) : List[T] = if (isEmpty) Nil else if (n <= 0) this else tail.drop(n - 1)
def map[U](f : T => U) : List[U] = if (isEmpty) Nil else if(head) :: tail.map(f)

List Construction

let's first check the an examples 
class Fruit
class Apple extends Fruit
class Orange extends Fruit

val apples = new Apple : NIl // type List[Apple]

val fruits = new Orange :: apples // type List[Fruit]

how is that happening. 

// how ?
// flexibility is from the :: methods.
def ::[U >: T] (x : U) : List[U] = new scala.::(x, this)

and this ist he ::: method. 

// the ::: method
def :::[U >: T] (prefix : List[U]) 
  if (prefix.isEmpty) this
  else prefix.head :: prefix.tail ::: this
however, you have to be careful when you use the List class, e.g. suppose that we increment each of the element in a list. 

// -- the ListBuffer class
// List operation, not tail-recursive
  def incAll(xs : List[Int]) :: List[Int] = xs match {
    case List() => LIst()
    case x : xs1 => x + 1 :: incAll(xs1)
  }
this is not effecient because it is not tail recursive, and it has limitation on the size of elements that it can process. 

and you may revise the code with For expressoin, again it is not effecient. 

// another not effecient way 
var result = List[Int]()
for (x <- xs ) result = result ::: List(x + 1) // ::: time proportional to the length of the list. 
result
the more effecient way is to use ListBuffer, the code below. 

// effecient, and ListBuffer
val buf = new ListBuffer[Int]
for (x <- xs) buf += x + 1
buf.toList

List class practise

We may goes into the List class details. doing so we know some system design practises which can be very useful experience on making our own library code or design our own systems. 

first, check the map method we have.  

// Map method in List. 
final override def map[U] (f : T => U) : List[U] = {
  val b = new ListBuffer[U]
  var these = this
  while (!these.isEmpty) {
    b += f(these.head)
    these = these.tail
    
  }
  b.toList
}
and the real definition of the :: class has the following 

// real definition of the :: class
final case class ::[U](hd : U, private[scala] var tl : List[U]) extends List[U] {
  def head = hd
  def tail = tl
  override def isEmpty : Boolean = false
}
note on the above code

  1. tl is var
  2. private[scala] qualifier on tl
reason, more effecient, because when tail is constructed , List buf can still access the List
ListBuffer may have something similar to this:

final class ListBuffer[T] extends Buffer[T] {
  private var start : List[T] = Nil
  private var last0 : ::[T] = _
  private var exported : Boolean = false
  override def toList : List[T] = { 
    exported = !start.isEmpty
    start
  }
  override def += (x: T) {
    if (exported) copy()
    if (start.isEmpty) { 
      last0 = new scala.::(x, Nil)
      start = last0
    } else { 
      val last1 = last0 // join the last0 and last1.. 
      last0  = new scala::(x, Nil)
      last1.tl = last0
    }
  }
  // ... 
}
toList is a very cheap and effecient. 

Functional outside

This is yet another design principle, where a strategy that scala uses, trying to combine purity with effeciency by carefully delimiting the effects of impure operations.




转载于:https://my.oschina.net/u/854138/blog/142294

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值