Skip to content

Commit 011d224

Browse files
authored
Expand stream module (#1028)
1 parent 454efda commit 011d224

File tree

6 files changed

+84
-25
lines changed

6 files changed

+84
-25
lines changed

effekt/shared/src/main/scala/effekt/core/PolymorphismBoxing.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,7 @@ object PolymorphismBoxing extends Phase[CoreTransformed, CoreTransformed] {
476476
// Do strings need to be boxed? Really?
477477
case core.Type.TString => Pure.Literal("<?nothing>", core.Type.TString)
478478
case core.Type.TByte => Pure.Literal(1337, core.Type.TByte)
479+
case core.Type.TChar => Pure.Literal('a', core.Type.TChar)
479480
case t if box.isDefinedAt(t) => sys error s"No default value defined for ${t}"
480481
case _ => sys error s"Trying to unbox Nothing to ${t}"
481482
}

examples/stdlib/stream/sum_of_squares.effekt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def main() = {
1111
println("The sum of squares from 1 to " ++ show(max) ++ " is:")
1212
println(sum {
1313
with boundary
14-
with limit[Int](max + 1)
14+
with limit[Int](max)
1515
squares()
1616
})
1717
}

examples/stdlib/stream/taylor.effekt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ def ints(): Unit / emit[Int] = {
1010
def take[A](n: Int) { stream: () => Unit / emit[A] }: List[A] = {
1111
with collectList[A]
1212
with boundary
13-
with limit[A](n + 1)
13+
with limit[A](n)
1414
stream()
1515
}
1616

examples/stdlib/stream/tee.check

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ a{ ... }
33
2
44
3
55
4
6-
5
76
Cons(1, Cons(2, Cons(3, Cons(4, Nil()))))
87
a done
98
b{ ... }
@@ -16,59 +15,54 @@ b{ ... }
1615
7
1716
8
1817
9
19-
10
2018
Cons(1, Cons(2, Cons(3, Cons(4, Cons(5, Cons(6, Cons(7, Cons(8, Cons(9, Nil())))))))))
2119
b done
2220
tee{a}{b}{ ... }
2321
1
2422
2
2523
3
2624
4
27-
5
2825
Cons(1, Cons(2, Cons(3, Cons(4, Nil()))))
2926
a done
27+
5
3028
6
3129
7
3230
8
3331
9
34-
10
3532
Cons(1, Cons(2, Cons(3, Cons(4, Cons(5, Cons(6, Cons(7, Cons(8, Cons(9, Nil())))))))))
3633
b done
3734
tee{b}{a}{ ... }
3835
1
3936
2
4037
3
4138
4
42-
5
4339
Cons(1, Cons(2, Cons(3, Cons(4, Nil()))))
4440
a done
41+
5
4542
6
4643
7
4744
8
4845
9
49-
10
5046
Cons(1, Cons(2, Cons(3, Cons(4, Cons(5, Cons(6, Cons(7, Cons(8, Cons(9, Nil())))))))))
5147
b done
5248
a{ teeing{b}{ ... } }
5349
1
5450
2
5551
3
5652
4
57-
5
5853
Cons(1, Cons(2, Cons(3, Cons(4, Nil()))))
5954
a done
6055
b{ teeing{a}{ ... } }
6156
1
6257
2
6358
3
6459
4
65-
5
6660
Cons(1, Cons(2, Cons(3, Cons(4, Nil()))))
6761
a done
62+
5
6863
6
6964
7
7065
8
7166
9
72-
10
7367
Cons(1, Cons(2, Cons(3, Cons(4, Cons(5, Cons(6, Cons(7, Cons(8, Cons(9, Nil())))))))))
7468
b done

examples/stdlib/stream/tee.effekt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ def main() = {
1111
}
1212
}
1313
def a{ b: => Unit / emit[Int] }: Unit = {
14-
println(collectList[Int]{boundary{limit[Int](5){b}}})
14+
println(collectList[Int]{boundary{limit[Int](4){b}}})
1515
println("a done")
1616
}
1717
def b{ b: => Unit / emit[Int] }: Unit = {
18-
println(collectList[Int]{boundary{limit[Int](10){b}}})
18+
println(collectList[Int]{boundary{limit[Int](9){b}}})
1919
println("b done")
2020
}
2121
println("a{ ... }")

libraries/common/stream.effekt

Lines changed: 76 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,18 @@ effect stop(): Nothing
3030
def for[A] { stream: () => Unit / emit[A] } { action: A => Unit }: Unit =
3131
returning::for[A, Unit]{stream}{action}
3232

33+
/// Applies the given function on each emitted element and reemits the result.
34+
///
35+
/// e.g. map[Int,String]{ x => x.show } { range(0, 5) }
36+
def map[A, B] { function: A => B } { stream: () => Unit / emit[A] }: Unit / emit[B] =
37+
returning::map[A, B, Unit]{function}{stream}
38+
39+
/// Runs the given action whenever the given reader reads an element.
40+
///
41+
/// e.g. var i = -1; with tap { i = i + 1; i }; reader()
42+
def tap[A] { action: () => A / stop } { reader: () => Unit / read[A] }: Unit =
43+
returning::tap[A, Unit]{action}{reader}
44+
3345
/// Runs the stream as a message queue,
3446
/// handling each of its elements that can produce new elements ("messages"),
3547
/// until a fixed point is reached.
@@ -162,8 +174,8 @@ def index[A] { stream: () => Unit / emit[A] }: Unit / emit[Indexed[A]] =
162174

163175

164176
/// If `number` is zero or negative it does nothing
165-
def limit[A](number: Int) { stream: () => Unit / emit[A] }: Unit / {emit[A], stop} =
166-
returning::limit[A, Unit](number){stream}
177+
def limit[A](number: Int) { stream: () => Unit / emit[A] }: Unit / emit[A] =
178+
boundary { returning::limit[A, Unit](number){stream} }
167179

168180

169181
/// If `number` is zero or negative it does nothing
@@ -405,6 +417,12 @@ def encodeUTF8[R] { stream: () => R / emit[Char] }: R / emit[Byte] =
405417
resume(encodeChar(char))
406418
}
407419

420+
def writeFileUTF8[R](path: String) { stream: () => R / emit[Char] }: R / Exception[IOError] =
421+
writeFile(path) { encodeUTF8 { stream() } }
422+
423+
def readFileUTF8[R](path: String) { reader: () => R / read[Char] }: R / Exception[IOError] =
424+
readFile(path) { decodeUTF8 { reader() } }
425+
408426
def feed[R](string: String) { reader: () => R / read[Char] } =
409427
feed(string.fromString) {
410428
decodeUTF8 {
@@ -422,6 +440,12 @@ def each(string: String): Unit / emit[Char] =
422440
def collectString { stream: () => Unit / emit[Char] }: String =
423441
returning::collectString[Unit]{stream}.second
424442

443+
def writeLine { body: () => Unit / emit[Char] }: Unit / emit[Char] =
444+
returning::writeLine[Unit]{body}
445+
446+
def readLine { body: () => Unit / read[Char] }: Unit / {read[Char], stop} =
447+
returning::readLine[Unit]{body}
448+
425449
namespace internal {
426450
effect snapshot(): Unit
427451
}
@@ -515,6 +539,20 @@ def for[A, R] { stream: () => R / emit[A] } { action: A => Unit }: R =
515539
resume(action(value))
516540
}
517541

542+
def map[A, B, R] { function: A => B } { stream: () => R / emit[A] }: R / emit[B] =
543+
try {
544+
stream()
545+
} with emit[A] { value =>
546+
resume(do emit(function(value)))
547+
}
548+
549+
def tap[A, R] { action: () => A / stop } { reader: () => R / read[A] }: R =
550+
try {
551+
reader()
552+
} with read[A] { () =>
553+
resume { action() }
554+
}
555+
518556
def boundary[R] { program: () => R / stop }: Option[R] =
519557
try {
520558
Some(program())
@@ -542,17 +580,21 @@ def index[A, R] { stream: () => R / emit[A] }: R / emit[Indexed[A]] = {
542580

543581
/// If `number` is zero or negative it does nothing
544582
def limit[A, R](number: Int) { stream: () => R / emit[A] }: R / { emit[A], stop } = {
545-
if (number <= 0) do stop();
546-
var i = 1;
547-
try {
548-
stream()
549-
} with emit[A] { v =>
550-
if (i < number) {
551-
i = i + 1;
552-
resume(do emit(v))
553-
} else {
554-
do stop()
583+
if (number > 0) {
584+
var i = number;
585+
try {
586+
stream()
587+
} with emit[A] { v =>
588+
do emit(v);
589+
i = i - 1;
590+
if (i > 0) {
591+
resume(())
592+
} else {
593+
do stop()
594+
}
555595
}
596+
} else {
597+
do stop()
556598
}
557599
}
558600

@@ -615,6 +657,28 @@ def collectString[R] { stream: () => R / emit[Char] }: (R, String) = {
615657
(result, bytes.toString)
616658
}
617659

660+
def writeLine[R] { body: () => R / emit[Char] }: R / emit[Char] = {
661+
val result = body()
662+
do emit('\n')
663+
return result
664+
}
665+
666+
def readLine[R] { body: () => R / read[Char] }: R / {read[Char], stop} = {
667+
var stopped = false
668+
try {
669+
body()
670+
} with read[Char] {
671+
if(stopped){
672+
resume { do stop() }
673+
} else {
674+
do read[Char] match {
675+
case '\n' => stopped = true; resume { do stop() }
676+
case char => resume { return char }
677+
}
678+
}
679+
}
680+
}
681+
618682
def source[A, R] { stream: () => Unit / emit[A] } { reader: () => R / read[A] }: R = {
619683
var next = box { None() }
620684
next = box {

0 commit comments

Comments
 (0)