Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor 'stream', add a few examples #705

Merged
merged 10 commits into from
Nov 25, 2024
2 changes: 2 additions & 0 deletions examples/stdlib/stream/fibonacci.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The first 10 Fibonacci numbers:
Cons(0, Cons(1, Cons(1, Cons(2, Cons(3, Cons(5, Cons(8, Cons(13, Cons(21, Cons(34, Nil()))))))))))
20 changes: 20 additions & 0 deletions examples/stdlib/stream/fibonacci.effekt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import stream

def main() = {
val max = 10

val fibs = collectList[Int] {
var a = 0
var b = 1

replicate(max) {
val current = a
val next = a + b
a = b
b = next
current
}
}
println("The first " ++ show(max) ++ " Fibonacci numbers:")
println(fibs)
}
35 changes: 35 additions & 0 deletions examples/stdlib/stream/neighbours.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
The immediate neighbours of [4, 3] are:
[3, 2]
[3, 3]
[3, 4]
[4, 2]
[4, 4]
[5, 2]
[5, 3]
[5, 4]

The neighbours and their neighbours of [4, 3] are:
[2, 1]
[2, 2]
[2, 3]
[2, 4]
[2, 5]
[3, 1]
[3, 2]
[3, 3]
[3, 4]
[3, 5]
[4, 1]
[4, 2]
[4, 4]
[4, 5]
[5, 1]
[5, 2]
[5, 3]
[5, 4]
[5, 5]
[6, 1]
[6, 2]
[6, 3]
[6, 4]
[6, 5]
38 changes: 38 additions & 0 deletions examples/stdlib/stream/neighbours.effekt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import stream

record Pos(x: Int, y: Int)

def equals(left: Pos, right: Pos) = (left, right) match {
case (Pos(lx, ly), Pos(rx, ry)) => lx == rx && ly == ry
}

def show(p: Pos) = "[" ++ show(p.x) ++ ", " ++ show(p.y) ++ "]"

/// Gets the neighbours of a given position.
/// with radius=1, those are immediate neighbours (including the diagonal)
/// with radius=2, these are neighbours&their neighbours
/// ...
def neighboursOf(pos: Pos, radius: Int) = {
with val dx = for[Int] { range(neg(radius), radius + 1) }
with val dy = for[Int] { range(neg(radius), radius + 1) }
val newPosition = Pos(pos.x + dx, pos.y + dy)
do emit(newPosition)
}
jiribenes marked this conversation as resolved.
Show resolved Hide resolved

def main() = {
val start = Pos(4, 3)

println("The immediate neighbours of " ++ show(start) ++ " are:")
for[Pos] { start.neighboursOf(1) } {
case p and not(p.equals(start)) => println(show(p))
case _ => ()
}

println("")

println("The neighbours and their neighbours of " ++ show(start) ++ " are:")
for[Pos] { start.neighboursOf(2) } {
case p and not(p.equals(start)) => println(show(p))
case _ => ()
}
}
2 changes: 2 additions & 0 deletions examples/stdlib/stream/sum_of_squares.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The sum of squares from 1 to 10 is:
385
12 changes: 12 additions & 0 deletions examples/stdlib/stream/sum_of_squares.effekt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import stream

def squares(max: Int): Unit / emit[Int] = {
with val n = for[Int] { range(1, max) }
do emit(n * n)
}

def main() = {
val max = 10
println("The sum of squares from 1 to " ++ show(max) ++ " is:")
println(sum { squares(max + 1) })
}
jiribenes marked this conversation as resolved.
Show resolved Hide resolved
3 changes: 3 additions & 0 deletions examples/stdlib/stream/zip.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
1, a
2, b
3, c
12 changes: 12 additions & 0 deletions examples/stdlib/stream/zip.effekt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import stream
jiribenes marked this conversation as resolved.
Show resolved Hide resolved

def main() = {
def stream1() = [1, 2, 3].each
def stream2() = array::fromList(["a", "b", "c", "d"]).each

with val tup = for[(Int, String)] {
zip[Int, String] { stream1 } { stream2 }
}
val (a, b) = tup
jiribenes marked this conversation as resolved.
Show resolved Hide resolved
println(show(a) ++ ", " ++ show(b))
}
33 changes: 28 additions & 5 deletions libraries/common/stream.effekt
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def boundary[R] { program: () => R / stop }: Option[R] =
try {
Some(program())
} with stop {
def stop() = None()
None()
}

def exhaustively[A] { program: () => A / stop } { action: A => Unit }: Unit =
Expand All @@ -102,9 +102,20 @@ def exhaustively[A] { program: () => A / stop } { action: A => Unit }: Unit =
}
go()
} with stop {
def stop() = ()
()
}
jiribenes marked this conversation as resolved.
Show resolved Hide resolved

/// Run `program` forever until `stop` is thrown.
def exhaustively[A] { program: () => A / stop }: Unit =
try {
def go(): Unit = {
program()
go()
}
go()
} with stop {
()
}

// In Effekt lower bounds are inclusive and upper bounds are exclusive

Expand Down Expand Up @@ -216,7 +227,7 @@ def collectBytes[R] { stream: () => R / emit[Byte] }: (R, ByteArray) = {
def collectBytes { stream: () => Unit / emit[Byte] }: ByteArray =
collectBytes[Unit]{stream}.second

def feed[T](list: List[T]) { reader: () => Unit / read[T] } = {
def feed[T](list: List[T]) { reader: () => Unit / read[T] }: Unit = {
var l = list
try {
reader()
Expand All @@ -232,7 +243,7 @@ def feed[T](list: List[T]) { reader: () => Unit / read[T] } = {
}
}

def feed[T](array: Array[T]) { reader: () => Unit / read[T] } = {
def feed[T](array: Array[T]) { reader: () => Unit / read[T] }: Unit = {
var i = 0
try {
reader()
Expand All @@ -247,7 +258,7 @@ def feed[T](array: Array[T]) { reader: () => Unit / read[T] } = {
}
}

def feed(bytes: ByteArray) { reader: () => Unit / read[Byte] } = {
def feed(bytes: ByteArray) { reader: () => Unit / read[Byte] }: Unit = {
var i = 0
try {
reader()
Expand Down Expand Up @@ -282,6 +293,18 @@ def source[A, R] { stream: () => Unit / emit[A] } { reader: () => R / read[A] }:
}
}

/// Combines two streams together producing a stream of pairs in lockstep.
/// Given two streams of length `n` and `m`, it produces a stream of length `min(n, m)`.
def zip[A, B] { stream1: () => Unit / emit[A] } { stream2: () => Unit / emit[B] }: Unit / emit[(A, B)] = {
with source[A, Unit] { stream1 }
with source[B, Unit] { stream2 }

exhaustively {
val a = do read[A]()
val b = do read[B]()
do emit((a, b))
}
}
jiribenes marked this conversation as resolved.
Show resolved Hide resolved

def writeFile[R](path: String) { stream: () => R / emit[Byte] }: R / Exception[IOError] = {

Expand Down
Loading