Skip to content

Commit

Permalink
Refactor 'stream', add a few examples (#705)
Browse files Browse the repository at this point in the history
'stream' got slightly refactored (using `Any` everywhere now),
fixed a few bugs, added a few examples of push streams, pull streams,
their infinite variants, `limit`, `zip`, ...

---------

Co-authored-by: Philipp Schuster <[email protected]>
  • Loading branch information
jiribenes and phischu authored Nov 25, 2024
1 parent 1ec022e commit b034213
Show file tree
Hide file tree
Showing 16 changed files with 255 additions and 41 deletions.
6 changes: 5 additions & 1 deletion effekt/jvm/src/test/scala/effekt/StdlibTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ abstract class StdlibChezTests extends StdlibTests {
override def ignored: List[File] = List(
// Not implemented yet
examplesDir / "stdlib" / "bytearray",
examplesDir / "stdlib" / "io"
examplesDir / "stdlib" / "io",
examplesDir / "stdlib" / "stream" / "characters.effekt",
examplesDir / "stdlib" / "stream" / "fuse_newlines.effekt"
)
}
class StdlibChezSchemeMonadicTests extends StdlibChezTests {
Expand All @@ -44,6 +46,8 @@ class StdlibLLVMTests extends StdlibTests {

// Valgrind leak/failure
examplesDir / "stdlib" / "bytearray" / "bytearray.effekt",
examplesDir / "stdlib" / "stream" / "characters.effekt",
examplesDir / "stdlib" / "stream" / "fuse_newlines.effekt",
examplesDir / "stdlib" / "io" / "filesystem" / "async_file_io.effekt",
examplesDir / "stdlib" / "io" / "filesystem" / "files.effekt",
examplesDir / "stdlib" / "io" / "filesystem" / "wordcount.effekt",
Expand Down
3 changes: 2 additions & 1 deletion examples/benchmarks/input_output/word_count_ascii.effekt
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ def countWords(): Output / read[Byte] = {
var lines = 0
var wasSpace = true

exhaustively { do read[Byte]() } { c =>
exhaustively {
val c = do read[Byte]()

chars = chars + 1

Expand Down
3 changes: 2 additions & 1 deletion examples/benchmarks/input_output/word_count_utf8.effekt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ def countWords(): Output / read[Char] = {
var lines = 0
var wasSpace = true

exhaustively[Char] { do read() } { c =>
exhaustively {
val c = do read[Char]()

chars = chars + 1

Expand Down
6 changes: 6 additions & 0 deletions examples/stdlib/stream/characters.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
H (72)
e (101)
l (108)
l (108)
o (111)
Cons(H, Cons(e, Cons(l, Cons(l, Cons(o, Nil())))))
11 changes: 11 additions & 0 deletions examples/stdlib/stream/characters.effekt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import stream

def main() = {
for[Char] { each("Hello") } { c =>
println(show(c) ++ " (" ++ show(c.toInt) ++ ")")
}

val list = collectList[Char] { each("Hello") }
println(list.map { c => c.show })
}

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)
}
3 changes: 3 additions & 0 deletions examples/stdlib/stream/fuse_newlines.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ab
c
de
32 changes: 32 additions & 0 deletions examples/stdlib/stream/fuse_newlines.effekt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import stream

def fuseNewlines(): Nothing / {read[Char], emit[Char], stop} = {
val c = do read[Char]()
if (c == '\n') {
do emit(c)
skipNewlines()
} else {
do emit(c)
fuseNewlines()
}
}

def skipNewlines(): Nothing / {read[Char], emit[Char], stop} = {
val c = do read[Char]()
if (c == '\n') {
skipNewlines()
} else {
do emit(c)
fuseNewlines()
}
}

def main() = {
with feed("ab\n\nc\nde")
println(collectString {
with exhaustively
fuseNewlines()
})
}


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)
}

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
16 changes: 16 additions & 0 deletions examples/stdlib/stream/sum_of_squares.effekt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import stream

def squares(): Unit / emit[Int] =
for[Int] { rangeFrom(1) } { n =>
do emit(n * n)
}


def main() = {
val max = 10
println("The sum of squares from 1 to " ++ show(max) ++ " is:")
println(sum {
with limit[Int](max + 1)
squares()
})
}
5 changes: 5 additions & 0 deletions examples/stdlib/stream/zip.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
1, H
2, e
3, l
4, l
5, o
11 changes: 11 additions & 0 deletions examples/stdlib/stream/zip.effekt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import stream

def main() = {
def stream1() = rangeFrom(1)
// Ideally this would be an array to demonstrate the capabilities.
def stream2() = ['H', 'e', 'l', 'l', 'o'].each

zip[Int, Char]{stream1}{stream2} { (a, b) =>
println(show(a) ++ ", " ++ show(b))
}
}
Loading

0 comments on commit b034213

Please sign in to comment.