Skip to content

Commit 41b2cfa

Browse files
committed
experiment
1 parent 4d0c810 commit 41b2cfa

File tree

2 files changed

+111
-17
lines changed

2 files changed

+111
-17
lines changed

corout.fdoc

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
I will show a simple low level example of coroutines, it will be a
66
simple pipeline consisting of a source, a transducer, a limiter, and a sink.
77

8+
@h2 The source
89
First we have our source, which just write all the integers starting from 0
910
down the channel @{out}. The type @{%>int} is an output channel endpoint
1011
for @{int}.
@@ -19,6 +20,7 @@ proc source (out: %>int) () {
1920
}
2021
@
2122

23+
@h2 The sink
2224
Now we have a simple sink, which just prints everything it reads:
2325
@tangle ex1
2426
proc sink (inp: %<int) () {
@@ -35,6 +37,7 @@ unit -> unit
3537
@
3638
which is the type required to spawn fibre from a coroutine.
3739

40+
@h2 The transducer
3841
Now we have a transducer which writes the square of every integer it reads.
3942
@tangle ex1
4043
proc squarer (inp: %<int, out: %>int) () {
@@ -45,6 +48,7 @@ proc squarer (inp: %<int, out: %>int) () {
4548
}
4649
@
4750

51+
@h2 The limiter
4852
You should notice the previous three components were all infinite loops.
4953
Since we don't want our demo to run forever we will throw in a limiter chip:
5054
@tangle ex1
@@ -60,6 +64,7 @@ This procedure drops through, but it cannot return control, because
6064
there is nowhere to return it to, so it has, in effect, committed
6165
suicide implicitly.
6266

67+
@h2 The runner
6368
Now we need have four components so we need three channels to connect them:
6469
@tangle ex1
6570
proc run_pipeline() {
@@ -86,6 +91,7 @@ run_pipeline();
8691
@
8792

8893
Here is the complete program: <a href="https://github.com/felix-lang/felix-lang.github.io/blob/main/examples/ex1.flx">ex1.flx</a>
94+
8995
@h1 Using the chip DSSL
9096
The code above involves a bit of boilerplate so I'm going to show you how to do the
9197
same job using the <em>chip</em> DSSL. A DSSL is a unique feature of Felix which allows
@@ -178,6 +184,44 @@ run_pipeline2();
178184
For any functional programmers around, a pipeline is semantically identical
179185
to a Monad.
180186

187+
@h2 How does it stop?
188+
It is clear, because I told you, that we put the @{limiter} into the pipeline so it terminates.
189+
So the @{limiter} commits suicide by dropping off the end after a certain number of data transfers.
190+
But the other three components are infinite loops, so how does the system terminate?
191+
192+
First consider the transducer @{squarer} tries to write to the limiter, but alas, it is dead?
193+
The write stalls, and we say the fibre is <em>blocked</em> or being vulgar, <em>constipated</em>.
194+
And now, since it is blocked, it cannot read the input from the @{source}, so it too is blocked.
195+
196+
The @{sink} on the other hand has a different problem: it is trying to read from the @{limiter}
197+
but the limiter is dead, so there is no input coming: the sink is said to be @{starved}.
198+
199+
There are therefore <em>no active fibres</em> so the system terminates.
200+
I will emphasise this point heavily because these are the correct termination semantics.
201+
There is another language with processes and channels, namely @{golang}.
202+
Unfortunately @{golang} got the termination semantics completely wrong.
203+
in addition, @{golang} channel semantics are also wrong because channels can be closed
204+
and a reader can detect if a writer closed the channel.
205+
206+
Although this is not possible in Felix, you can write the option type @{opt} and use
207+
the @{None} case to signal end of data. In fact, in Felix you can write <em>any</em>
208+
type down a channel, even channels!
209+
210+
@h1 Felix is a coroutine
211+
Most programming language generate programs which consist of single top level procedure,
212+
for example @{main()} in C. It is a subroutine called by the startup code which in turn
213+
was invoked by the operating system.
214+
215+
Felix, as usual, is different. For a start, Felix generates libraries, in fact the
216+
default is a shared library. So in fact, what you think is mainline code running
217+
is in fact just the initialisation code for the library. You can also
218+
add a procedure @{flx_main()} to your code and that will also be run after
219+
the initialisation of the library.
220+
221+
However there is something else different: the Felix mainline code is not
222+
a subroutine, it is a coroutine!
223+
224+
181225
@h1 The concept of fibration
182226
A <em>coroutine system</em> is a collection of processes called <em>fibres</em>
183227
with these properties:

corout.html

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,14 @@
348348
}
349349
var allbuttons = [
350350
"A low level example.",
351+
"The source",
352+
"The sink",
353+
"The transducer",
354+
"The limiter",
355+
"The runner",
351356
"Using the chip DSSL",
357+
"How does it stop?",
358+
"Felix is a coroutine",
352359
"The concept of fibration",
353360
"next",
354361
"high",
@@ -416,21 +423,30 @@
416423
<!--Left Margin Toc Main Contents-->
417424
<div class=m1 onclick="mshow('menu1','#A low level example._h')"> <a href="#A_low_level_example._h">A low level example.</a></div>
418425
<div class=sm id=menu1>
426+
<div class=m2><a href="#The_source_h">The source</a></div>
427+
<div class=m2><a href="#The_sink_h">The sink</a></div>
428+
<div class=m2><a href="#The_transducer_h">The transducer</a></div>
429+
<div class=m2><a href="#The_limiter_h">The limiter</a></div>
430+
<div class=m2><a href="#The_runner_h">The runner</a></div>
419431
</div>
420432
<div class=m1 onclick="mshow('menu2','#Using the chip DSSL_h')"> <a href="#Using_the_chip_DSSL_h">Using the chip DSSL</a></div>
421433
<div class=sm id=menu2>
434+
<div class=m2><a href="#How_does_it_stop?_h">How does it stop?</a></div>
422435
</div>
423-
<div class=m1 onclick="mshow('menu3','#The concept of fibration_h')"> <a href="#The_concept_of_fibration_h">The concept of fibration</a></div>
436+
<div class=m1 onclick="mshow('menu3','#Felix is a coroutine_h')"> <a href="#Felix_is_a_coroutine_h">Felix is a coroutine</a></div>
424437
<div class=sm id=menu3>
425-
<div class=m2><a href="#next_h">next</a></div>
426438
</div>
427-
<div class=m1 onclick="mshow('menu4','#high_h')"> <a href="#high_h">high</a></div>
439+
<div class=m1 onclick="mshow('menu4','#The concept of fibration_h')"> <a href="#The_concept_of_fibration_h">The concept of fibration</a></div>
428440
<div class=sm id=menu4>
441+
<div class=m2><a href="#next_h">next</a></div>
442+
</div>
443+
<div class=m1 onclick="mshow('menu5','#high_h')"> <a href="#high_h">high</a></div>
444+
<div class=sm id=menu5>
429445
<div class=m2><a href="#med1_h">med1</a></div>
430446
<div class=m2><a href="#med2_h">med2</a></div>
431447
<div class=m2><a href="#med3_h">med3</a></div>
432448
</div>
433-
<script>counter_max=4;</script>
449+
<script>counter_max=5;</script>
434450
</div>
435451
<!--End Left Margin Toc-->
436452

@@ -443,7 +459,8 @@
443459
<h1 id='A_low_level_example._h'><img src='/share/src/web/images/minus.gif' id='A low level example.' onclick='toggle(this,"A_low_level_example._d")' alt='+'/> 1 A low level example.</h1><div id='A_low_level_example._d' style='display:block'>
444460
<p>I will show a simple low level example of coroutines, it will be a
445461
simple pipeline consisting of a source, a transducer, a limiter, and a sink.
446-
</p><p>First we have our source, which just write all the integers starting from 0
462+
</p><h2 id='The_source_h'><img src='/share/src/web/images/minus.gif' id='The source' onclick='toggle(this,"The_source_d")' alt='+'/> 1.1 The source</h2><div id='The_source_d' style='display:block'>
463+
<p>First we have our source, which just write all the integers starting from 0
447464
down the channel <code>out</code>. The type <code>%>int</code> is an output channel endpoint
448465
for <code>int</code>.
449466
</p><pre class='inclusion'>
@@ -455,7 +472,8 @@ <h1 id='A_low_level_example._h'><img src='/share/src/web/images/minus.gif' id='A
455472
<span class="lineno" id=line5></span> ++i;
456473
<span class="lineno" id=line6></span> <span class="small_keyword" title="end of body">done</span>
457474
<span class="lineno" id=line7></span> }
458-
</pre></p><p>Now we have a simple sink, which just prints everything it reads:
475+
</pre></p></div><h2 id='The_sink_h'><img src='/share/src/web/images/minus.gif' id='The sink' onclick='toggle(this,"The_sink_d")' alt='+'/> 1.2 The sink</h2><div id='The_sink_d' style='display:block'>
476+
<p>Now we have a simple sink, which just prints everything it reads:
459477
</p><pre class='inclusion'>
460478
examples/ex1.flx</pre>
461479
<p><pre class='flxbg'><span class="lineno" id=line1></span> <span class="big_keyword" title="Define a procedure, a function with side-effects not returning a value">proc</span> sink (inp: %&lt;<span class="library" title="binding of C int type">int</span>) () {
@@ -468,7 +486,8 @@ <h1 id='A_low_level_example._h'><img src='/share/src/web/images/minus.gif' id='A
468486
procedure will have type
469487
</p><p><pre class='flxbg'><span class="lineno" id=line1></span> <span class="library" title="Type with one values (), the empty tuple">unit</span> -&gt; <span class="library" title="Type with one values (), the empty tuple">unit</span>
470488
</pre></p><p>which is the type required to spawn fibre from a coroutine.
471-
</p><p>Now we have a transducer which writes the square of every integer it reads.
489+
</p></div><h2 id='The_transducer_h'><img src='/share/src/web/images/minus.gif' id='The transducer' onclick='toggle(this,"The_transducer_d")' alt='+'/> 1.3 The transducer</h2><div id='The_transducer_d' style='display:block'>
490+
<p>Now we have a transducer which writes the square of every integer it reads.
472491
</p><pre class='inclusion'>
473492
examples/ex1.flx</pre>
474493
<p><pre class='flxbg'><span class="lineno" id=line1></span> <span class="big_keyword" title="Define a procedure, a function with side-effects not returning a value">proc</span> squarer (inp: %&lt;<span class="library" title="binding of C int type">int</span>, out: %&gt;<span class="library" title="binding of C int type">int</span>) () {
@@ -477,7 +496,8 @@ <h1 id='A_low_level_example._h'><img src='/share/src/web/images/minus.gif' id='A
477496
<span class="lineno" id=line4></span> <span class="library" title="Print a string to a stream">write</span> (out, i * i);
478497
<span class="lineno" id=line5></span> <span class="small_keyword" title="end of body">done</span>
479498
<span class="lineno" id=line6></span> }
480-
</pre></p><p>You should notice the previous three components were all infinite loops.
499+
</pre></p></div><h2 id='The_limiter_h'><img src='/share/src/web/images/minus.gif' id='The limiter' onclick='toggle(this,"The_limiter_d")' alt='+'/> 1.4 The limiter</h2><div id='The_limiter_d' style='display:block'>
500+
<p>You should notice the previous three components were all infinite loops.
481501
Since we don't want our demo to run forever we will throw in a limiter chip:
482502
</p><pre class='inclusion'>
483503
examples/ex1.flx</pre>
@@ -491,7 +511,8 @@ <h1 id='A_low_level_example._h'><img src='/share/src/web/images/minus.gif' id='A
491511
</pre></p><p>This procedure drops through, but it cannot return control, because
492512
there is nowhere to return it to, so it has, in effect, committed
493513
suicide implicitly.
494-
</p><p>Now we need have four components so we need three channels to connect them:
514+
</p></div><h2 id='The_runner_h'><img src='/share/src/web/images/minus.gif' id='The runner' onclick='toggle(this,"The_runner_d")' alt='+'/> 1.5 The runner</h2><div id='The_runner_d' style='display:block'>
515+
<p>Now we need have four components so we need three channels to connect them:
495516
</p><pre class='inclusion'>
496517
examples/ex1.flx</pre>
497518
<p><pre class='flxbg'><span class="lineno" id=line1></span> <span class="big_keyword" title="Define a procedure, a function with side-effects not returning a value">proc</span> run_pipeline() {
@@ -516,7 +537,7 @@ <h1 id='A_low_level_example._h'><img src='/share/src/web/images/minus.gif' id='A
516537
<span class="lineno" id=line20></span> }
517538
<span class="lineno" id=line21></span> run_pipeline();
518539
</pre></p><p>Here is the complete program: <a href="https://github.com/felix-lang/felix-lang.github.io/blob/main/examples/ex1.flx">ex1.flx</a>
519-
</p></div><h1 id='Using_the_chip_DSSL_h'><img src='/share/src/web/images/minus.gif' id='Using the chip DSSL' onclick='toggle(this,"Using_the_chip_DSSL_d")' alt='+'/> 2 Using the chip DSSL</h1><div id='Using_the_chip_DSSL_d' style='display:block'>
540+
</p></div></div><h1 id='Using_the_chip_DSSL_h'><img src='/share/src/web/images/minus.gif' id='Using the chip DSSL' onclick='toggle(this,"Using_the_chip_DSSL_d")' alt='+'/> 2 Using the chip DSSL</h1><div id='Using_the_chip_DSSL_d' style='display:block'>
520541
<p>The code above involves a bit of boilerplate so I'm going to show you how to do the
521542
same job using the <em>chip</em> DSSL. A DSSL is a unique feature of Felix which allows
522543
the <em>user</em> to define an extension to the existing language, which has an application
@@ -603,7 +624,36 @@ <h1 id='A_low_level_example._h'><img src='/share/src/web/images/minus.gif' id='A
603624
<span class="lineno" id=line4></span> run_pipeline2();
604625
</pre></p><p>For any functional programmers around, a pipeline is semantically identical
605626
to a Monad.
606-
</p></div><h1 id='The_concept_of_fibration_h'><img src='/share/src/web/images/minus.gif' id='The concept of fibration' onclick='toggle(this,"The_concept_of_fibration_d")' alt='+'/> 3 The concept of fibration</h1><div id='The_concept_of_fibration_d' style='display:block'>
627+
</p><h2 id='How_does_it_stop?_h'><img src='/share/src/web/images/minus.gif' id='How does it stop?' onclick='toggle(this,"How_does_it_stop?_d")' alt='+'/> 2.1 How does it stop?</h2><div id='How_does_it_stop?_d' style='display:block'>
628+
<p>It is clear, because I told you, that we put the <code>limiter</code> into the pipeline so it terminates.
629+
So the <code>limiter</code> commits suicide by dropping off the end after a certain number of data transfers.
630+
But the other three components are infinite loops, so how does the system terminate?
631+
</p><p>First consider the transducer <code>squarer</code> tries to write to the limiter, but alas, it is dead?
632+
The write stalls, and we say the fibre is <em>blocked</em> or being vulgar, <em>constipated</em>.
633+
And now, since it is blocked, it cannot read the input from the <code>source</code>, so it too is blocked.
634+
</p><p>The <code>sink</code> on the other hand has a different problem: it is trying to read from the <code>limiter</code>
635+
but the limiter is dead, so there is no input coming: the sink is said to be <code>starved</code>.
636+
</p><p>There are therefore <em>no active fibres</em> so the system terminates.
637+
I will emphasise this point heavily because these are the correct termination semantics.
638+
There is another language with processes and channels, namely <code>golang</code>.
639+
Unfortunately <code>golang</code> got the termination semantics completely wrong.
640+
in addition, <code>golang</code> channel semantics are also wrong because channels can be closed
641+
and a reader can detect if a writer closed the channel.
642+
</p><p>Although this is not possible in Felix, you can write the option type <code>opt</code> and use
643+
the <code>None</code> case to signal end of data. In fact, in Felix you can write <em>any</em>
644+
type down a channel, even channels!
645+
</p></div></div><h1 id='Felix_is_a_coroutine_h'><img src='/share/src/web/images/minus.gif' id='Felix is a coroutine' onclick='toggle(this,"Felix_is_a_coroutine_d")' alt='+'/> 3 Felix is a coroutine</h1><div id='Felix_is_a_coroutine_d' style='display:block'>
646+
<p>Most programming language generate programs which consist of single top level procedure,
647+
for example <code>main()</code> in C. It is a subroutine called by the startup code which in turn
648+
was invoked by the operating system.
649+
</p><p>Felix, as usual, is different. For a start, Felix generates libraries, in fact the
650+
default is a shared library. So in fact, what you think is mainline code running
651+
is in fact just the initialisation code for the library. You can also
652+
add a procedure <code>flx_main()</code> to your code and that will also be run after
653+
the initialisation of the library.
654+
</p><p>However there is something else different: the Felix mainline code is not
655+
a subroutine, it is a coroutine!
656+
</p></div><h1 id='The_concept_of_fibration_h'><img src='/share/src/web/images/minus.gif' id='The concept of fibration' onclick='toggle(this,"The_concept_of_fibration_d")' alt='+'/> 4 The concept of fibration</h1><div id='The_concept_of_fibration_d' style='display:block'>
607657
<p>A <em>coroutine system</em> is a collection of processes called <em>fibres</em>
608658
with these properties:
609659
<ul>
@@ -664,13 +714,13 @@ <h1 id='A_low_level_example._h'><img src='/share/src/web/images/minus.gif' id='A
664714
</p><p>In addition, I/O transfers always result in the reader proceeding,
665715
to give it a chance to actually fetch the data before the write
666716
might modify it.
667-
</p><h2 id='next_h'><img src='/share/src/web/images/minus.gif' id='next' onclick='toggle(this,"next_d")' alt='+'/> 3.1 next</h2><div id='next_d' style='display:block'>
717+
</p><h2 id='next_h'><img src='/share/src/web/images/minus.gif' id='next' onclick='toggle(this,"next_d")' alt='+'/> 4.1 next</h2><div id='next_d' style='display:block'>
668718
<p>stuff
669719
</p><p><pre class='flxbg'><span class="lineno" id=line1></span> blah
670720
</pre></p><p>stuff
671-
</p></div></div><h1 id='high_h'><img src='/share/src/web/images/minus.gif' id='high' onclick='toggle(this,"high_d")' alt='+'/> 4 high</h1><div id='high_d' style='display:block'>
721+
</p></div></div><h1 id='high_h'><img src='/share/src/web/images/minus.gif' id='high' onclick='toggle(this,"high_d")' alt='+'/> 5 high</h1><div id='high_d' style='display:block'>
672722
<p>blam
673-
</p><h2 id='med1_h'><img src='/share/src/web/images/minus.gif' id='med1' onclick='toggle(this,"med1_d")' alt='+'/> 4.1 med1</h2><div id='med1_d' style='display:block'>
723+
</p><h2 id='med1_h'><img src='/share/src/web/images/minus.gif' id='med1' onclick='toggle(this,"med1_d")' alt='+'/> 5.1 med1</h2><div id='med1_d' style='display:block'>
674724
<p>stuff
675725
stuff
676726
stuff
@@ -707,13 +757,13 @@ <h1 id='A_low_level_example._h'><img src='/share/src/web/images/minus.gif' id='A
707757
stuff
708758
stuff
709759
stuff
710-
</p></div><h2 id='med2_h'><img src='/share/src/web/images/minus.gif' id='med2' onclick='toggle(this,"med2_d")' alt='+'/> 4.2 med2</h2><div id='med2_d' style='display:block'>
760+
</p></div><h2 id='med2_h'><img src='/share/src/web/images/minus.gif' id='med2' onclick='toggle(this,"med2_d")' alt='+'/> 5.2 med2</h2><div id='med2_d' style='display:block'>
711761
<p>stuff
712-
</p></div><h2 id='med3_h'><img src='/share/src/web/images/minus.gif' id='med3' onclick='toggle(this,"med3_d")' alt='+'/> 4.3 med3</h2><div id='med3_d' style='display:block'>
762+
</p></div><h2 id='med3_h'><img src='/share/src/web/images/minus.gif' id='med3' onclick='toggle(this,"med3_d")' alt='+'/> 5.3 med3</h2><div id='med3_d' style='display:block'>
713763
<p>stuff <em>inline html works</em>
714764
but we have <code>micros</code> for inline code as well.
715765
<a href= https://www.itkservices2.com/nem_review_1.2>See ITK stuff</a>
716-
</p><h3 id='low_h'><img src='/share/src/web/images/minus.gif' id='low' onclick='toggle(this,"low_d")' alt='+'/> 4.3.1 low</h3><div id='low_d' style='display:block'>
766+
</p><h3 id='low_h'><img src='/share/src/web/images/minus.gif' id='low' onclick='toggle(this,"low_d")' alt='+'/> 5.3.1 low</h3><div id='low_d' style='display:block'>
717767
<p>level 3 stuff
718768
</p><p><pre class='flxbg'><span class="lineno" id=line1></span> blah
719769
</pre></p><p>stuff

0 commit comments

Comments
 (0)