Given an interface Stream
:
trait Stream[A] {
def head: A
def tail: Stream[A]
}
Write the functions zeroes
, ones
, and
twos
, which return streams of values 0
,
1
, and 2
:
def zeroes: Stream[Int] = ???
// 0 -> 0 -> 0 -> 0 -> ...
def ones: Stream[Int] = ???
// 1 -> 1 -> 1 -> 1 -> ...
def twos: Stream[Int] = ???
// 2 -> 2 -> 2 -> 2 -> ...
Write the functions evens
and odds
, which
return streams of the even natural numbers (0, 2, 4, ...) and the odd
natural numbers (1, 3, 5, ...):
def evens: Stream[Int] = ???
// 0 -> 2 -> 4 -> 6 -> ...
def odds: Stream[Int] = ???
// 1 -> 3 -> 5 -> 7 -> ...
Write the function combine
, which interleaves its
argument streams in constant time:
def combine[A](ss: Stream[A] *): Stream[A] = ???
// combine(evens, odds) = 0 -> 1 -> 2 -> 3 -> ...
object ConstantsStreams {
class ConstantsStream(value: Int) extends Stream[Int] {
def head: Int = value
def tail: Stream[Int] = this
}
def zeroes: Stream[Int] =
new ConstantsStream(0)
def ones: Stream[Int] =
new ConstantsStream(1)
def twos: Stream[Int] =
new ConstantsStream(2)
}
object NatsStreams {
class ByTwosStream(value: Int) extends Stream[Int] {
def head: Int = value
def tail: Stream[Int] = new ByTwosStream(value + 2)
}
def evens: Stream[Int] =
new ByTwosStream(0)
def odds: Stream[Int] =
new ByTwosStream(1)
}
object CombinedStreams {
class InterleavedStream[A](ss: Stream[A] *) extends Stream[A] {
def head: A = ss.head.head
def tail: Stream[A] =
new InterleavedStream((ss.tail :+ ss.head.tail):_*)
}
def combine[A](ss: Stream[A] *): Stream[A] =
new InterleavedStream[A](ss:_*)
}
object Streams extends App {
def peek[A](s: Stream[A]): String =
s"${s.head} -> ${s.tail.head} -> ${s.tail.tail.head} -> ${s.tail.tail.tail.head} -> ..."
println()
print(
s"""|Constants streams:
| zeroes = ${peek(ConstantsStreams.zeroes)}
| ones = ${peek(ConstantsStreams.ones)}
| twos = ${peek(ConstantsStreams.twos)}
|""".stripMargin
)
println()
print(
s"""|Natural numbers streams:
| evens = ${peek(NatsStreams.evens)}
| odds = ${peek(NatsStreams.odds)}
|""".stripMargin
)
println()
print(
s"""|Combined streams:
| combine(evens, odds) = ${peek(CombinedStreams.combine(NatsStreams.evens, NatsStreams.odds))}
|""".stripMargin
)
}
This file is literate Scala, and can be run using Codedown:
$ curl https://earldouglas.com/posts/exercises/scala-streams.md |
codedown scala | xargs -0 scala -nc -e
Constants streams:
zeroes = 0 -> 0 -> 0 -> 0 -> ...
ones = 1 -> 1 -> 1 -> 1 -> ...
twos = 2 -> 2 -> 2 -> 2 -> ...
Natural numbers streams:
evens = 0 -> 2 -> 4 -> 6 -> ...
odds = 1 -> 3 -> 5 -> 7 -> ...
Combined streams:
combine(evens, odds) = 0 -> 1 -> 2 -> 3 -> ...