Skip to content

Commit c31a517

Browse files
oforeroOscar Foreropivovarit
authored
SCALA-481: LazyList in Scala (#525)
Co-authored-by: Oscar Forero <[email protected]> Co-authored-by: Grzegorz Piwowarek <[email protected]>
1 parent e2ad2d7 commit c31a517

File tree

5 files changed

+118
-1
lines changed

5 files changed

+118
-1
lines changed

build.sbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,4 +376,4 @@ lazy val scala3_libraries = (project in file("scala3-libraries"))
376376
)
377377
)
378378

379-
testOptions in Test += Tests.Argument(TestFrameworks.ScalaTest, "-eG")
379+
testOptions in Test += Tests.Argument(TestFrameworks.ScalaTest, "-eG")
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.baeldung.scala.lazylists
2+
3+
sealed trait SimpleLazyList[+T] {
4+
def empty: Boolean
5+
def head: T
6+
def tail: SimpleLazyList[T]
7+
8+
def ::[S >: T](e: S): SimpleLazyList[S] = #:@:(e, this)
9+
10+
def !!(n: Int): T = n match {
11+
case 1 => head
12+
case n => tail.!!(n - 1)
13+
}
14+
}
15+
16+
case object SLNil extends SimpleLazyList[Nothing] {
17+
override def head = throw new IllegalArgumentException("Head of empty list")
18+
override def tail = throw new IllegalArgumentException("Tail of empty list")
19+
override val empty: Boolean = true
20+
}
21+
22+
class #:@:[T](_head: => T, _tail: => SimpleLazyList[T]) extends SimpleLazyList[T] {
23+
override val empty: Boolean = true
24+
override lazy val head: T = _head
25+
override lazy val tail: SimpleLazyList[T] = _tail
26+
}
27+
28+
object #:@: {
29+
def apply[T](head: => T, tail: => SimpleLazyList[T]) = new #:@:(head, tail)
30+
def unapply[T](slcons: #:@:[T]): Option[(T, SimpleLazyList[T])] = Some((slcons.head, slcons.tail))
31+
}
32+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.baeldung.scala.lazylists
2+
3+
sealed trait SimpleList[+T] {
4+
def empty: Boolean
5+
def head: T
6+
def tail: SimpleList[T]
7+
def !!(n: Int): T = n match {
8+
case 1 => head
9+
case n => tail.!!(n - 1)
10+
}
11+
}
12+
case object SNil extends SimpleList[Nothing] {
13+
override def head = throw new IllegalArgumentException("Head of empty list")
14+
override def tail = throw new IllegalArgumentException("Tail of empty list")
15+
override val empty: Boolean = true
16+
}
17+
case class :@:[T](head: T, tail: SimpleList[T]) extends SimpleList[T] {
18+
override val empty: Boolean = true
19+
}
20+
21+
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.baedung.scala.lazylists
2+
3+
import com.baeldung.scala.lazylists.{#:@:, SLNil, SimpleLazyList}
4+
import org.scalatest.wordspec.AnyWordSpec
5+
6+
7+
class SimpleLazyListSpec extends AnyWordSpec {
8+
"A list" should {
9+
"Allow the creation of a one Element list" in {
10+
assertResult(5)((5 :: SLNil).head)
11+
}
12+
"A Simple Lazy List can represent a Fibonacci sequence without throwing a Stack Overflow" in {
13+
def fibonacci(current: Int = 0, next: Int = 1): SimpleLazyList[Int] = #:@:(current, fibonacci(next, current + next))
14+
assertResult(8)(fibonacci().!!(7))
15+
}
16+
"The head of the Simple Lazy List is strict" in {
17+
var side = "No side effect"
18+
val list = #:@:(
19+
{
20+
side = "Side effect"
21+
side
22+
},
23+
SLNil
24+
)
25+
assertResult("Side effect")(side)
26+
}
27+
"The head of a Scala Lazy List is lazy" in {
28+
var side = "No side effect"
29+
val list =
30+
{
31+
side = "Side effect"
32+
side
33+
} #:: LazyList.empty
34+
assertResult("No side effect")(side)
35+
list.map(x => {
36+
side = "Another side effect"
37+
x.toUpperCase
38+
})
39+
assertResult("No side effect")(side)
40+
list.filter(x => x.startsWith("Side"))
41+
assertResult("No side effect")(side)
42+
println(list.head)
43+
assertResult("Side effect")(side)
44+
}
45+
}
46+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.baedung.scala.lazylists
2+
3+
import com.baeldung.scala.lazylists.{SimpleList, :@:, SLNil}
4+
import org.scalatest.wordspec.AnyWordSpec
5+
6+
class SimpleListSpec extends AnyWordSpec {
7+
"A list" should {
8+
"Allow the creation of a one Element list" in {
9+
assertResult(5)((5 :: SLNil).head)
10+
}
11+
"Throw and Stack Overflow Exception if used to define a Fibonacci sequence" in {
12+
intercept[StackOverflowError] {
13+
def fibonacci(current: Int = 0, next: Int = 1): SimpleList[Int] = :@:(current, fibonacci(next, current + 1))
14+
assertResult(8)(fibonacci().!!(7))
15+
}
16+
}
17+
}
18+
}

0 commit comments

Comments
 (0)