@effekt-lang/effekt 0.10.0 → 0.12.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.
package/bin/effekt CHANGED
Binary file
@@ -11,7 +11,7 @@ import io/error
11
11
  /// Describes push streams by emitting values of type `A`.
12
12
  effect emit[A](value: A): Unit
13
13
 
14
- /// Describes pull streams by requiring values of type `A`.
14
+ /// Describes pull streams by reading values of type `A`.
15
15
  ///
16
16
  /// The producer can decide to `stop` emitting values.
17
17
  effect read[A](): A / stop
@@ -28,20 +28,14 @@ def for[A, R] { stream: () => R / emit[A] } { action: A => Unit }: R =
28
28
  resume(action(value))
29
29
  }
30
30
 
31
- /// Like `for[A, R]`, but fixes the result of producing computation to the
32
- /// common type `Unit`. This simplifies annotating the type of stream
33
- /// elements `A` without having to also annotate `R`.
31
+ /// Like `for[A, R]`, but ignores the result of the stream, and consequently
32
+ /// works for any type. Use this to annotate the type of stream elements
33
+ /// `A` without having to also annotate `R`.
34
34
  ///
35
35
  /// e.g. for[Int] { prog() } { el => println(el) }
36
- def for[A] { stream: () => Unit / emit[A] } { action: A => Unit }: Unit =
37
- for[A, Unit]{stream}{action}
38
-
39
- def continually[A] { action: () => A }: Nothing / emit[A] = {
40
- def go(): Nothing = {
41
- do emit(action())
42
- go()
43
- }
44
- go()
36
+ def for[A] { stream: () => Any / emit[A] } { action: A => Unit }: Unit = {
37
+ for[A, Any]{stream}{action}
38
+ ()
45
39
  }
46
40
 
47
41
  /// Turns a `list` into a producer of a push stream
@@ -91,23 +85,28 @@ def boundary[R] { program: () => R / stop }: Option[R] =
91
85
  try {
92
86
  Some(program())
93
87
  } with stop {
94
- def stop() = None()
88
+ None()
95
89
  }
96
90
 
97
- def exhaustively[A] { program: () => A / stop } { action: A => Unit }: Unit =
91
+ def boundary { program: () => Any / stop }: Unit = {
92
+ boundary[Any]{program}
93
+ ()
94
+ }
95
+
96
+ /// Run `program` forever until `stop` is thrown.
97
+ def exhaustively { program: () => Any / stop }: Unit =
98
98
  try {
99
99
  def go(): Unit = {
100
- action(program())
100
+ program()
101
101
  go()
102
102
  }
103
103
  go()
104
104
  } with stop {
105
- def stop() = ()
105
+ ()
106
106
  }
107
107
 
108
108
 
109
- // In Effekt lower bounds are inclusive and upper bounds are exclusive
110
-
109
+ /// In Effekt lower bounds are inclusive and upper bounds are exclusive
111
110
  record Indexed[A](index: Int, value: A)
112
111
 
113
112
  def range(lower: Int, upper: Int): Unit / emit[Int] =
@@ -137,7 +136,7 @@ def index[A, R] { stream: () => R / emit[A] }: R / emit[Indexed[A]] = {
137
136
  }
138
137
 
139
138
  /// If `number` is zero or negative it does nothing
140
- def take[A, R](number: Int) { stream: () => R / emit[A] }: R / { emit[A], stop } = {
139
+ def limit[A, R](number: Int) { stream: () => R / emit[A] }: R / { emit[A], stop } = {
141
140
  if (number <= 0) do stop();
142
141
  var i = 1;
143
142
  try {
@@ -152,6 +151,13 @@ def take[A, R](number: Int) { stream: () => R / emit[A] }: R / { emit[A], stop }
152
151
  }
153
152
  }
154
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
+ }
159
+
160
+
155
161
  /// If `number` is zero or negative it does nothing
156
162
  def replicate[A](number: Int) { action: () => A }: Unit / emit[A] =
157
163
  if (number > 0) {
@@ -170,8 +176,8 @@ def sum[R] { stream : () => R / emit[Int] }: (R, Int) = {
170
176
  }
171
177
  }
172
178
 
173
- def sum { stream : () => Unit / emit[Int] }: Int =
174
- sum[Unit]{stream}.second
179
+ def sum { stream : () => Any / emit[Int] }: Int =
180
+ sum[Any]{stream}.second
175
181
 
176
182
  def collectList[A, R] { stream: () => R / emit[A] }: (R, List[A]) =
177
183
  try {
@@ -181,8 +187,8 @@ def collectList[A, R] { stream: () => R / emit[A] }: (R, List[A]) =
181
187
  (r, Cons(v, vs))
182
188
  }
183
189
 
184
- def collectList[A] { stream: () => Unit / emit[A] }: List[A] =
185
- collectList[A, Unit]{stream}.second
190
+ def collectList[A] { stream: () => Any / emit[A] }: List[A] =
191
+ collectList[A, Any]{stream}.second
186
192
 
187
193
  def collectArray[A, R] { stream: () => R / emit[A] }: (R, Array[A]) = {
188
194
  var i = 0
@@ -197,8 +203,8 @@ def collectArray[A, R] { stream: () => R / emit[A] }: (R, Array[A]) = {
197
203
  }
198
204
  }
199
205
 
200
- def collectArray[A] { stream: () => Unit / emit[A] }: Array[A] =
201
- collectArray[A, Unit]{stream}.second
206
+ def collectArray[A] { stream: () => Any / emit[A] }: Array[A] =
207
+ collectArray[A, Any]{stream}.second
202
208
 
203
209
  def collectBytes[R] { stream: () => R / emit[Byte] }: (R, ByteArray) = {
204
210
  var i = 0
@@ -213,10 +219,10 @@ def collectBytes[R] { stream: () => R / emit[Byte] }: (R, ByteArray) = {
213
219
  }
214
220
  }
215
221
 
216
- def collectBytes { stream: () => Unit / emit[Byte] }: ByteArray =
217
- collectBytes[Unit]{stream}.second
222
+ def collectBytes { stream: () => Any / emit[Byte] }: ByteArray =
223
+ collectBytes[Any]{stream}.second
218
224
 
219
- def feed[T](list: List[T]) { reader: () => Unit / read[T] } = {
225
+ def feed[T, R](list: List[T]) { reader: () => R / read[T] }: R = {
220
226
  var l = list
221
227
  try {
222
228
  reader()
@@ -232,14 +238,16 @@ def feed[T](list: List[T]) { reader: () => Unit / read[T] } = {
232
238
  }
233
239
  }
234
240
 
235
- def feed[T](array: Array[T]) { reader: () => Unit / read[T] } = {
241
+ def feed[T, R](array: Array[T]) { reader: () => R / read[T] }: R = {
236
242
  var i = 0
237
243
  try {
238
244
  reader()
239
245
  } with read[T] {
240
246
  resume {
241
247
  if (i < array.size) {
242
- array.unsafeGet(i)
248
+ val c = i
249
+ i = c + 1
250
+ array.unsafeGet(c)
243
251
  } else {
244
252
  do stop()
245
253
  }
@@ -247,14 +255,16 @@ def feed[T](array: Array[T]) { reader: () => Unit / read[T] } = {
247
255
  }
248
256
  }
249
257
 
250
- def feed(bytes: ByteArray) { reader: () => Unit / read[Byte] } = {
258
+ def feed[R](bytes: ByteArray) { reader: () => R / read[Byte] }: R = {
251
259
  var i = 0
252
260
  try {
253
261
  reader()
254
262
  } with read[Byte] {
255
263
  resume {
256
264
  if (i < bytes.size) {
257
- bytes.unsafeGet(i)
265
+ val c = i
266
+ i = c + 1
267
+ bytes.unsafeGet(c)
258
268
  } else {
259
269
  do stop()
260
270
  }
@@ -262,7 +272,7 @@ def feed(bytes: ByteArray) { reader: () => Unit / read[Byte] } = {
262
272
  }
263
273
  }
264
274
 
265
- def source[A, R] { stream: () => Unit / emit[A] } { reader: () => R / read[A] }: R = {
275
+ def source[A, R] { stream: () => Any / emit[A] } { reader: () => R / read[A] }: R = {
266
276
  var next = box { None() }
267
277
  next = box {
268
278
  try {
@@ -282,6 +292,21 @@ def source[A, R] { stream: () => Unit / emit[A] } { reader: () => R / read[A] }:
282
292
  }
283
293
  }
284
294
 
295
+ def source[A] { stream: () => Any / emit[A] } { reader: () => Any / read[A] }: Unit = {
296
+ source[A, Any]{stream}{reader}
297
+ ()
298
+ }
299
+
300
+ /// 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 = {
303
+ with source[A] { stream1 }
304
+ with source[B] { stream2 }
305
+
306
+ exhaustively {
307
+ action(do read[A](), do read[B]())
308
+ }
309
+ }
285
310
 
286
311
  def writeFile[R](path: String) { stream: () => R / emit[Byte] }: R / Exception[IOError] = {
287
312
 
@@ -407,13 +432,15 @@ def feed(string: String) { reader: () => Unit / read[Char] } =
407
432
 
408
433
  def each(string: String): Unit / emit[Char] =
409
434
  feed(string) {
410
- exhaustively[Char] { do read() } { char => do emit(char) }
435
+ exhaustively {
436
+ do emit[Char](do read[Char]())
437
+ }
411
438
  }
412
439
 
413
440
  def collectString[R] { stream: () => R / emit[Char] }: (R, String) = {
414
- val (result, bytes) = collectBytes { encodeUTF8 { stream } }
441
+ val (result, bytes) = collectBytes[R] { encodeUTF8 { stream } }
415
442
  (result, bytes.toString)
416
443
  }
417
444
 
418
- def collectString { stream: () => Unit / emit[Char] }: String =
419
- collectString[Unit]{stream}.second
445
+ def collectString { stream: () => Any / emit[Char] }: String =
446
+ collectString[Any]{stream}.second
@@ -113,22 +113,23 @@ function SHIFT(p, body, ks, k) {
113
113
  cont = { stack: meta.stack, prompt: meta.prompt, backup: meta.arena.backup(), rest: cont }
114
114
  meta = meta.rest
115
115
 
116
- function resumeComp(c, ks, k) {
117
- let meta = { stack: k, prompt: ks.prompt, arena: ks.arena, rest: ks.rest }
118
- let toRewind = cont
119
- while (!!toRewind) {
120
- meta = { stack: toRewind.stack, prompt: toRewind.prompt, arena: toRewind.backup(), rest: meta }
121
- toRewind = toRewind.rest
122
- }
116
+ const k1 = meta.stack
117
+ meta.stack = null
118
+ return body(cont, meta, k1)
119
+ }
123
120
 
124
- const k2 = meta.stack // TODO instead copy meta here, like elsewhere?
125
- meta.stack = null
126
- return () => c(meta, k2)
121
+ // Rewind stack `cont` back onto `k` :: `ks` and resume with c
122
+ function RESUME(cont, c, ks, k) {
123
+ let meta = { stack: k, prompt: ks.prompt, arena: ks.arena, rest: ks.rest }
124
+ let toRewind = cont
125
+ while (!!toRewind) {
126
+ meta = { stack: toRewind.stack, prompt: toRewind.prompt, arena: toRewind.backup(), rest: meta }
127
+ toRewind = toRewind.rest
127
128
  }
128
129
 
129
- let k1 = meta.stack
130
+ const k1 = meta.stack // TODO instead copy meta here, like elsewhere?
130
131
  meta.stack = null
131
- return body(resumeComp, meta, k1)
132
+ return () => c(meta, k1)
132
133
  }
133
134
 
134
135
  function RUN_TOPLEVEL(comp) {
@@ -210,4 +211,4 @@ $effekt.run = RUN
210
211
  *
211
212
  * If a runtime is available, use `$effekt.run`, instead.
212
213
  */
213
- $effekt.runToplevel = RUN_TOPLEVEL
214
+ $effekt.runToplevel = RUN_TOPLEVEL
@@ -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=1731870966"><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=1733080574"><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 fa-linkedin 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=1731870966"></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=1733080574"></script>
61
61
  <script>(function(){})(jQuery,document)</script></div></body></html>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@effekt-lang/effekt",
3
3
  "author": "Jonathan Brachthäuser",
4
- "version": "0.10.0",
4
+ "version": "0.12.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/effekt-lang/effekt.git"