@effekt-lang/effekt 0.14.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,24 +19,13 @@ effect read[A](): A / stop
19
19
  /// Signal from a producer to a consumer that there are no further values.
20
20
  effect stop(): Nothing
21
21
 
22
- /// Canonical handler of push streams that performs `action` for every
23
- /// value emitted by `stream`.
24
- def for[A, R] { stream: () => R / emit[A] } { action: A => Unit }: R =
25
- try {
26
- stream()
27
- } with emit[A] { value =>
28
- resume(action(value))
29
- }
30
-
31
22
  /// Like `for[A, R]`, but ignores the result of the stream, and consequently
32
23
  /// works for any type. Use this to annotate the type of stream elements
33
24
  /// `A` without having to also annotate `R`.
34
25
  ///
35
26
  /// e.g. for[Int] { prog() } { el => println(el) }
36
- def for[A] { stream: () => Any / emit[A] } { action: A => Unit }: Unit = {
37
- for[A, Any]{stream}{action}
38
- ()
39
- }
27
+ def for[A] { stream: () => Unit / emit[A] } { action: A => Unit }: Unit =
28
+ returning::for[A, Unit]{stream}{action}
40
29
 
41
30
  /// Turns a `list` into a producer of a push stream
42
31
  /// by emitting each contained value left-to-right.
@@ -81,20 +70,13 @@ def each(bytes: ByteArray): Unit / emit[Byte] = {
81
70
  // not seq
82
71
 
83
72
 
84
- def boundary[R] { program: () => R / stop }: Option[R] =
85
- try {
86
- Some(program())
87
- } with stop {
88
- None()
89
- }
90
-
91
- def boundary { program: () => Any / stop }: Unit = {
92
- boundary[Any]{program}
73
+ def boundary { program: () => Unit / stop }: Unit = {
74
+ returning::boundary[Unit]{program}
93
75
  ()
94
76
  }
95
77
 
96
78
  /// Run `program` forever until `stop` is thrown.
97
- def exhaustively { program: () => Any / stop }: Unit =
79
+ def exhaustively { program: () => Unit / stop }: Unit =
98
80
  try {
99
81
  def go(): Unit = {
100
82
  program()
@@ -105,6 +87,24 @@ def exhaustively { program: () => Any / stop }: Unit =
105
87
  ()
106
88
  }
107
89
 
90
+ def many[A] { action: () => A / stop }: Unit / emit[A] =
91
+ exhaustively { do emit(action()) }
92
+
93
+ def some[A] { action: () => A / stop }: Unit / { emit[A], stop } = {
94
+ do emit(action())
95
+ many { action() }
96
+ }
97
+
98
+ def optionally { program: () => Unit / stop }: Bool =
99
+ returning::optionally[Unit]{program}.isDefined
100
+
101
+ def attempt[R] { program: () => R / stop } { fallback: () => R }: R =
102
+ try {
103
+ program()
104
+ } with stop {
105
+ fallback()
106
+ }
107
+
108
108
 
109
109
  /// In Effekt lower bounds are inclusive and upper bounds are exclusive
110
110
  record Indexed[A](index: Int, value: A)
@@ -123,39 +123,13 @@ def rangeFrom(lower: Int): Unit / emit[Int] = {
123
123
  rangeFrom(lower + 1)
124
124
  }
125
125
 
126
+ def index[A] { stream: () => Unit / emit[A] }: Unit / emit[Indexed[A]] =
127
+ returning::index[A, Unit]{stream}
126
128
 
127
- def index[A, R] { stream: () => R / emit[A] }: R / emit[Indexed[A]] = {
128
- var i = 0;
129
- try {
130
- stream()
131
- } with emit[A] { v =>
132
- val c = i;
133
- i = c + 1;
134
- resume(do emit(Indexed(c, v)))
135
- }
136
- }
137
129
 
138
130
  /// If `number` is zero or negative it does nothing
139
- def limit[A, R](number: Int) { stream: () => R / emit[A] }: R / { emit[A], stop } = {
140
- if (number <= 0) do stop();
141
- var i = 1;
142
- try {
143
- stream()
144
- } with emit[A] { v =>
145
- if (i < number) {
146
- i = i + 1;
147
- resume(do emit(v))
148
- } else {
149
- do stop()
150
- }
151
- }
152
- }
153
-
154
- /// If `number` is zero or negative it does nothing
155
- def limit[A](number: Int) { stream: () => Any / emit[A] }: Unit / emit[A] =
156
- boundary {
157
- limit[A, Any](number){stream}
158
- }
131
+ def limit[A](number: Int) { stream: () => Unit / emit[A] }: Unit / {emit[A], stop} =
132
+ returning::limit[A, Unit](number){stream}
159
133
 
160
134
 
161
135
  /// If `number` is zero or negative it does nothing
@@ -166,61 +140,17 @@ def replicate[A](number: Int) { action: () => A }: Unit / emit[A] =
166
140
  }
167
141
 
168
142
 
169
- def sum[R] { stream : () => R / emit[Int] }: (R, Int) = {
170
- var s = 0;
171
- try {
172
- (stream(), s)
173
- } with emit[Int] { v =>
174
- s = s + v;
175
- resume(())
176
- }
177
- }
143
+ def sum { stream : () => Unit / emit[Int] }: Int =
144
+ returning::sum[Unit]{stream}.second
178
145
 
179
- def sum { stream : () => Any / emit[Int] }: Int =
180
- sum[Any]{stream}.second
146
+ def collectList[A] { stream: () => Unit / emit[A] }: List[A] =
147
+ returning::collectList[A, Unit]{stream}.second
181
148
 
182
- def collectList[A, R] { stream: () => R / emit[A] }: (R, List[A]) =
183
- try {
184
- (stream(), Nil())
185
- } with emit[A] { (v) =>
186
- val (r, vs) = resume(());
187
- (r, Cons(v, vs))
188
- }
189
-
190
- def collectList[A] { stream: () => Any / emit[A] }: List[A] =
191
- collectList[A, Any]{stream}.second
192
-
193
- def collectArray[A, R] { stream: () => R / emit[A] }: (R, Array[A]) = {
194
- var i = 0
195
- var a = array::allocate(1)
196
- try {
197
- (stream(), a.resize(i))
198
- } with emit[A] { (v) =>
199
- if (i >= a.size) { a = a.resize(2 * a.size) }
200
- a.unsafeSet(i, v)
201
- i = i + 1
202
- resume(())
203
- }
204
- }
205
-
206
- def collectArray[A] { stream: () => Any / emit[A] }: Array[A] =
207
- collectArray[A, Any]{stream}.second
208
-
209
- def collectBytes[R] { stream: () => R / emit[Byte] }: (R, ByteArray) = {
210
- var i = 0
211
- var a = bytearray::allocate(1)
212
- try {
213
- (stream(), a.resize(i))
214
- } with emit[Byte] { (v) =>
215
- if (i >= a.size) { a = a.resize(2 * a.size) }
216
- a.unsafeSet(i, v)
217
- i = i + 1
218
- resume(())
219
- }
220
- }
149
+ def collectArray[A] { stream: () => Unit / emit[A] }: Array[A] =
150
+ returning::collectArray[A, Unit]{stream}.second
221
151
 
222
- def collectBytes { stream: () => Any / emit[Byte] }: ByteArray =
223
- collectBytes[Any]{stream}.second
152
+ def collectBytes { stream: () => Unit / emit[Byte] }: ByteArray =
153
+ returning::collectBytes[Unit]{stream}.second
224
154
 
225
155
  def feed[T, R](list: List[T]) { reader: () => R / read[T] }: R = {
226
156
  var l = list
@@ -272,34 +202,12 @@ def feed[R](bytes: ByteArray) { reader: () => R / read[Byte] }: R = {
272
202
  }
273
203
  }
274
204
 
275
- def source[A, R] { stream: () => Any / emit[A] } { reader: () => R / read[A] }: R = {
276
- var next = box { None() }
277
- next = box {
278
- try {
279
- stream()
280
- None()
281
- } with emit[A] { (v) =>
282
- next = box { resume(()) }
283
- Some(v)
284
- }
285
- }
286
- try {
287
- reader()
288
- } with read[A] {
289
- resume {
290
- next().getOrElse { do stop() }
291
- }
292
- }
293
- }
294
-
295
- def source[A] { stream: () => Any / emit[A] } { reader: () => Any / read[A] }: Unit = {
296
- source[A, Any]{stream}{reader}
297
- ()
298
- }
205
+ def source[A] { stream: () => Unit / emit[A] } { reader: () => Unit / read[A] }: Unit =
206
+ returning::source[A, Unit]{stream}{reader}
299
207
 
300
208
  /// Combines two streams together producing a stream of pairs in lockstep.
301
- /// Given two streams of length `n` and `m`, it produces a stream of length `min(n, m)`.
302
- def zip[A, B] { stream1: () => Any / emit[A] } { stream2: () => Any / emit[B] } { action: (A, B) => Any }: Unit = {
209
+ /// Terminates when either of them terminates.
210
+ def zip[A, B] { stream1: () => Unit / emit[A] } { stream2: () => Unit / emit[B] } { action: (A, B) => Unit }: Unit = {
303
211
  with source[A] { stream1 }
304
212
  with source[B] { stream2 }
305
213
 
@@ -423,7 +331,7 @@ def encodeUTF8[R] { stream: () => R / emit[Char] }: R / emit[Byte] =
423
331
  resume(encodeChar(char))
424
332
  }
425
333
 
426
- def feed(string: String) { reader: () => Unit / read[Char] } =
334
+ def feed[R](string: String) { reader: () => R / read[Char] } =
427
335
  feed(string.fromString) {
428
336
  decodeUTF8 {
429
337
  reader()
@@ -437,10 +345,129 @@ def each(string: String): Unit / emit[Char] =
437
345
  }
438
346
  }
439
347
 
348
+ def collectString { stream: () => Unit / emit[Char] }: String =
349
+ returning::collectString[Unit]{stream}.second
350
+
351
+ namespace returning {
352
+
353
+ /// Canonical handler of push streams that performs `action` for every
354
+ /// value emitted by `stream`.
355
+ def for[A, R] { stream: () => R / emit[A] } { action: A => Unit }: R =
356
+ try {
357
+ stream()
358
+ } with emit[A] { value =>
359
+ resume(action(value))
360
+ }
361
+
362
+ def boundary[R] { program: () => R / stop }: Option[R] =
363
+ try {
364
+ Some(program())
365
+ } with stop {
366
+ None()
367
+ }
368
+
369
+ def optionally[R] { program: () => R / stop }: Option[R] =
370
+ try {
371
+ Some(program())
372
+ } with stop {
373
+ None()
374
+ }
375
+
376
+ def index[A, R] { stream: () => R / emit[A] }: R / emit[Indexed[A]] = {
377
+ var i = 0;
378
+ try {
379
+ stream()
380
+ } with emit[A] { v =>
381
+ val c = i;
382
+ i = c + 1;
383
+ resume(do emit(Indexed(c, v)))
384
+ }
385
+ }
386
+
387
+ /// If `number` is zero or negative it does nothing
388
+ def limit[A, R](number: Int) { stream: () => R / emit[A] }: R / { emit[A], stop } = {
389
+ if (number <= 0) do stop();
390
+ var i = 1;
391
+ try {
392
+ stream()
393
+ } with emit[A] { v =>
394
+ if (i < number) {
395
+ i = i + 1;
396
+ resume(do emit(v))
397
+ } else {
398
+ do stop()
399
+ }
400
+ }
401
+ }
402
+
403
+ def sum[R] { stream : () => R / emit[Int] }: (R, Int) = {
404
+ var s = 0;
405
+ try {
406
+ (stream(), s)
407
+ } with emit[Int] { v =>
408
+ s = s + v;
409
+ resume(())
410
+ }
411
+ }
412
+
413
+ def collectList[A, R] { stream: () => R / emit[A] }: (R, List[A]) =
414
+ try {
415
+ (stream(), Nil())
416
+ } with emit[A] { (v) =>
417
+ val (r, vs) = resume(());
418
+ (r, Cons(v, vs))
419
+ }
420
+
421
+ def collectArray[A, R] { stream: () => R / emit[A] }: (R, Array[A]) = {
422
+ var i = 0
423
+ var a = array::allocate(1)
424
+ try {
425
+ (stream(), a.resize(i))
426
+ } with emit[A] { (v) =>
427
+ if (i >= a.size) { a = a.resize(2 * a.size) }
428
+ a.unsafeSet(i, v)
429
+ i = i + 1
430
+ resume(())
431
+ }
432
+ }
433
+
434
+ def collectBytes[R] { stream: () => R / emit[Byte] }: (R, ByteArray) = {
435
+ var i = 0
436
+ var a = bytearray::allocate(1)
437
+ try {
438
+ (stream(), a.resize(i))
439
+ } with emit[Byte] { (v) =>
440
+ if (i >= a.size) { a = a.resize(2 * a.size) }
441
+ a.unsafeSet(i, v)
442
+ i = i + 1
443
+ resume(())
444
+ }
445
+ }
446
+
440
447
  def collectString[R] { stream: () => R / emit[Char] }: (R, String) = {
441
448
  val (result, bytes) = collectBytes[R] { encodeUTF8 { stream } }
442
449
  (result, bytes.toString)
443
450
  }
444
451
 
445
- def collectString { stream: () => Any / emit[Char] }: String =
446
- collectString[Any]{stream}.second
452
+ def source[A, R] { stream: () => Unit / emit[A] } { reader: () => R / read[A] }: R = {
453
+ var next = box { None() }
454
+ next = box {
455
+ try {
456
+ stream()
457
+ next = box { None() }
458
+ None()
459
+ } with emit[A] { (v) =>
460
+ next = box { resume(()) }
461
+ Some(v)
462
+ }
463
+ }
464
+ try {
465
+ reader()
466
+ } with read[A] {
467
+ resume {
468
+ next().getOrElse { do stop() }
469
+ }
470
+ }
471
+ }
472
+
473
+ }
@@ -1,4 +1,4 @@
1
- <!doctype html><html lang=en><head><meta charset=utf-8><meta http-equiv=x-ua-compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><title>Eclipse Public License 2.0 (EPL) | The Eclipse Foundation</title><meta property="og:title" content="Eclipse Public License 2.0 (EPL) | The Eclipse Foundation"><meta name=twitter:title content="Eclipse Public License 2.0 (EPL) | The Eclipse Foundation"><meta name=description content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta property="og:description" content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta name=twitter:description content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta name=author content="Wayne Beaton"><link href=/favicon.ico rel=icon type=image/x-icon><meta property="og:image" content="https://www.eclipse.org/images/logos/eclipse-foundation-400x400.png"><meta name=twitter:image content="https://www.eclipse.org/images/logos/eclipse-foundation-400x400.png"><meta name=twitter:card content="summary"><meta name=twitter:site content="@eclipsefdn"><meta name=twitter:creator content="@eclipsefdn"><meta property="og:url" content="https://www.eclipse.org/legal/epl-2.0/"><meta property="og:type" content="website"><meta property="og:site_name" content="Eclipse Foundation"><meta name=keywords content="epl,epl-2.0,legal,foundation,eclipse,eclipse public license,license,licenses"><meta name=generator content="Hugo 0.110.0"><link rel=canonical href=https://www.eclipse.org/legal/epl-2.0/><link rel=alternate href=/legal/epl-2.0/index.xml type=application/rss+xml title><link rel=stylesheet href="/public/css/styles.css?v=1734290143"><script>(function(e,t,n,s,o){e[s]=e[s]||[],e[s].push({"gtm.start":(new Date).getTime(),event:"gtm.js"});var a=t.getElementsByTagName(n)[0],i=t.createElement(n),r=s!="dataLayer"?"&l="+s:"";i.async=!0,i.src="https://www.googletagmanager.com/gtm.js?id="+o+r,a.parentNode.insertBefore(i,a)})(window,document,"script","dataLayer","GTM-5WLCZXC")</script><script>var tableClasses="table"</script><link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel=stylesheet type=text/css></head><body><noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-5WLCZXC" height=0 width=0 style=display:none;visibility:hidden></iframe></noscript><a class=sr-only href=#content>Skip to main content</a><header class="header-wrapper header-wrapper" id=header><div class=header-toolbar><div class=container><div class=header-toolbar-row><div class="toolbar-btn toolbar-search-btn dropdown"><button class=dropdown-toggle id=toolbar-search type=button data-toggle=dropdown tabindex=0 aria-label=Search>
1
+ <!doctype html><html lang=en><head><meta charset=utf-8><meta http-equiv=x-ua-compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><title>Eclipse Public License 2.0 (EPL) | The Eclipse Foundation</title><meta property="og:title" content="Eclipse Public License 2.0 (EPL) | The Eclipse Foundation"><meta name=twitter:title content="Eclipse Public License 2.0 (EPL) | The Eclipse Foundation"><meta name=description content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta property="og:description" content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta name=twitter:description content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta name=author content="Wayne Beaton"><link href=/favicon.ico rel=icon type=image/x-icon><meta property="og:image" content="https://www.eclipse.org/images/logos/eclipse-foundation-400x400.png"><meta name=twitter:image content="https://www.eclipse.org/images/logos/eclipse-foundation-400x400.png"><meta name=twitter:card content="summary"><meta name=twitter:site content="@eclipsefdn"><meta name=twitter:creator content="@eclipsefdn"><meta property="og:url" content="https://www.eclipse.org/legal/epl-2.0/"><meta property="og:type" content="website"><meta property="og:site_name" content="Eclipse Foundation"><meta name=keywords content="epl,epl-2.0,legal,foundation,eclipse,eclipse public license,license,licenses"><meta name=generator content="Hugo 0.110.0"><link rel=canonical href=https://www.eclipse.org/legal/epl-2.0/><link rel=alternate href=/legal/epl-2.0/index.xml type=application/rss+xml title><link rel=stylesheet href="/public/css/styles.css?v=1734894944"><script>(function(e,t,n,s,o){e[s]=e[s]||[],e[s].push({"gtm.start":(new Date).getTime(),event:"gtm.js"});var a=t.getElementsByTagName(n)[0],i=t.createElement(n),r=s!="dataLayer"?"&l="+s:"";i.async=!0,i.src="https://www.googletagmanager.com/gtm.js?id="+o+r,a.parentNode.insertBefore(i,a)})(window,document,"script","dataLayer","GTM-5WLCZXC")</script><script>var tableClasses="table"</script><link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel=stylesheet type=text/css></head><body><noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-5WLCZXC" height=0 width=0 style=display:none;visibility:hidden></iframe></noscript><a class=sr-only href=#content>Skip to main content</a><header class="header-wrapper header-wrapper" id=header><div class=header-toolbar><div class=container><div class=header-toolbar-row><div class="toolbar-btn toolbar-search-btn dropdown"><button class=dropdown-toggle id=toolbar-search type=button data-toggle=dropdown tabindex=0 aria-label=Search>
2
2
  <i class="fa fa-search fa-lg" aria-role=none></i></button><div class="toolbar-search-bar-wrapper dropdown-menu dropdown-menu-right" aria-labelledby=toolbar-search><form action=https://www.eclipse.org/home/search method=get><div class=search-bar><input class=search-bar-input name=q placeholder=Search>
3
3
  <button>
4
4
  <i class="fa fa-search" type=submit></i></button></div></form></div></div><div class="toolbar-btn toolbar-user-menu-btn dropdown"><button class=dropdown-toggle id=toolbar-user-menu type=button data-toggle=dropdown tabindex=0 aria-label="User Menu">
@@ -57,5 +57,5 @@ open source software collaboration and innovation.</p></div><div class=mega-menu
57
57
  <i class="fa-brands fa-linkedin-in fa-stack-1x fa-inverse" aria-hidden=true></i>
58
58
  <span class=sr-only>Linkedin account</span></span></a></li></ul></div></div><div class="footer-sections row equal-height-md font-bold"><div class=col-md-15><div class=row><section id=footer-eclipse-foundation class="footer-section col-sm-8"><div class=menu-heading>Eclipse Foundation</div><ul class=nav><li><a href=https://www.eclipse.org/org/>About</a></li><li><a href=https://projects.eclipse.org/>Projects</a></li><li><a href=https://www.eclipse.org/collaborations/>Collaborations</a></li><li><a href=https://www.eclipse.org/membership/>Membership</a></li><li><a href=https://www.eclipse.org/sponsor/>Sponsor</a></li></ul></section><section id=footer-legal class="footer-section col-sm-8"><div class=menu-heading>Legal</div><ul class=nav><li><a href=https://www.eclipse.org/legal/privacy/>Privacy Policy</a></li><li><a href=https://www.eclipse.org/legal/terms-of-use/>Terms of Use</a></li><li><a href=https://www.eclipse.org/legal/compliance/>Compliance</a></li><li><a href=https://www.eclipse.org/org/documents/Community_Code_of_Conduct.php>Code of Conduct</a></li><li><a href=https://www.eclipse.org/legal/>Legal Resources</a></li><li><a class=toolbar-manage-cookies href=# onclick=event.preventDefault()>Manage Cookies</a></li></ul></section><section id=footer-more class="footer-section col-sm-8"><div class=menu-heading>More</div><ul class=nav><li><a href=https://www.eclipse.org/security/>Report a Vulnerability</a></li><li><a href=https://status.eclipse.org/>Service Status</a></li><li><a href=https://www.eclipse.org/org/foundation/contact.php>Contact Us</a></li><li><a href=https://www.eclipse.org/projects/support/>Support</a></li></ul></section></div></div><div id=footer-end class="footer-section col-md-8 col-md-offset-1 col-sm-24"><div class=footer-end-newsletter><form id=mc-embedded-subscribe-form action=https://eclipsecon.us6.list-manage.com/subscribe/post method=post novalidate target=_blank><label class=footer-end-newsletter-label for=email>Subscribe to our Newsletter</label><div class=footer-end-newsletter-input-wrapper><input class=footer-end-newsletter-input type=email id=email name=EMAIL autocomplete=email placeholder="Enter your email address"><div><i class="fa fa-solid fa-envelope fa-lg" aria-hidden=true></i></div></div><input type=hidden name=u value=eaf9e1f06f194eadc66788a85>
59
59
  <input type=hidden name=id value=46e57eacf1>
60
- <input id=mc-embedded-subscribe type=submit name=subscribe hidden></form></div></div></div><div class="col-sm-24 margin-top-20"><div class=row><div id=copyright class=col-md-16><p id=copyright-text>Copyright &copy; Eclipse Foundation AISBL. All Rights Reserved.</p></div></div></div><a href=# class=scrollup>Back to the top</a></div></footer><div id=footer-js><script src="/public/js/main.js?v1.0?v=1734290143"></script>
60
+ <input id=mc-embedded-subscribe type=submit name=subscribe hidden></form></div></div></div><div class="col-sm-24 margin-top-20"><div class=row><div id=copyright class=col-md-16><p id=copyright-text>Copyright &copy; Eclipse Foundation AISBL. All Rights Reserved.</p></div></div></div><a href=# class=scrollup>Back to the top</a></div></footer><div id=footer-js><script src="/public/js/main.js?v1.0?v=1734894944"></script>
61
61
  <script>(function(){})(jQuery,document)</script></div></body></html>