examples: shorten line lengths

FossilOrigin-Name: a7e5fe4c71047a01a833ce31583ef5597f3f0235c5a2fab90e55f07510bc0bf5
This commit is contained in:
crc 2021-01-27 14:54:38 +00:00
parent 45a1619f9e
commit 4c53181624
7 changed files with 112 additions and 45 deletions

View file

@ -1,12 +1,19 @@
# 1D Cellular Automota
Assume an array of cells with an initial distribution of live and dead cells, and imaginary cells off the end of the array having fixed values.
Assume an array of cells with an initial distribution of live
and dead cells, and imaginary cells off the end of the array
having fixed values.
Cells in the next generation of the array are calculated based on the value of the cell and its left and right nearest neighbours in the current generation.
Cells in the next generation of the array are calculated based
on the value of the cell and its left and right nearest neighbours
in the current generation.
If, in the following table, a live cell is represented by 1 and a dead cell by 0 then to generate the value of the cell at a particular index in the array of cellular values you use the following table:
If, in the following table, a live cell is represented by 1 and
a dead cell by 0 then to generate the value of the cell at a
particular index in the array of cellular values you use the
following table:
000 -> 0 #
000 -> 0 #
001 -> 0 #
010 -> 0 # Dies without enough neighbours
011 -> 1 # Needs one neighbour to survive
@ -15,15 +22,20 @@ If, in the following table, a live cell is represented by 1 and a dead cell by 0
110 -> 1 # Needs one neighbour to survive
111 -> 0 # Starved to death.
I had originally written an implementation of this in RETRO 11. For RETRO 12 I took advantage of new language features and some further considerations into the rules for this task.
I had originally written an implementation of this in RETRO 11. For
RETRO 12 I took advantage of new language features and some further
considerations into the rules for this task.
The first word, `string,` inlines a string to `here`. I'll use this to setup the initial input.
The first word, `string,` inlines a string to `here`. I'll use this to
setup the initial input.
~~~
:string, (s-) [ , ] s:for-each #0 , ;
~~~
The next two lines setup an initial generation and a buffer for the evolved generation. In this case, `This` is the current generation and `Next` reflects the next step in the evolution.
The next two lines setup an initial generation and a buffer for the
evolved generation. In this case, `This` is the current generation and
`Next` reflects the next step in the evolution.
~~~
'This d:create
@ -40,14 +52,16 @@ I use `display` to show the current generation.
&This s:put nl ;
~~~
As might be expected, `update` copies the `Next` generation to the `This` generation, setting things up for the next cycle.
As might be expected, `update` copies the `Next` generation to the
`This` generation, setting things up for the next cycle.
~~~
:update (-)
&Next &This dup s:length copy ;
~~~
The word `group` extracts a group of three cells. This data will be passed to `evolve` for processing.
The word `group` extracts a group of three cells. This data will be
passed to `evolve` for processing.
~~~
:group (a-nnn)
@ -56,9 +70,13 @@ The word `group` extracts a group of three cells. This data will be passed to `e
[ n:inc n:inc fetch ] tri ;
~~~
I use `evolve` to decide how a cell should change, based on its initial state with relation to its neighbors.
I use `evolve` to decide how a cell should change, based on its initial
state with relation to its neighbors.
In the prior implementation this part was much more complex as I tallied things up and had separate conditions for each combination. This time I take advantage of the fact that only cells with two neighbors will be alive in the next generation. So the process is:
In the prior implementation this part was much more complex as I tallied
things up and had separate conditions for each combination. This time I
take advantage of the fact that only cells with two neighbors will be
alive in the next generation. So the process is:
- take the data from `group`
- compare to `$#` (for living cells)
@ -72,21 +90,24 @@ In the prior implementation this part was much more complex as I tallied things
#-2 eq? [ $# ] [ $. ] choose ;
~~~
For readability I separated out the next few things. `at` takes an index and returns the address in `This` starting with the index.
For readability I separated out the next few things. `at` takes an index
and returns the address in `This` starting with the index.
~~~
:at (n-na)
&This over + ;
~~~
The `record` word adds the evolved value to a buffer. In this case my `generation` code will set the buffer to `Next`.
The `record` word adds the evolved value to a buffer. In this case my
`generation` code will set the buffer to `Next`.
~~~
:record (c-)
buffer:add n:inc ;
~~~
And now to tie it all together. Meet `generation`, the longest bit of code in this sample. It has several bits:
And now to tie it all together. Meet `generation`, the longest bit of
code in this sample. It has several bits:
- setup a new buffer pointing to `Next`
- this also preserves the old buffer
@ -105,7 +126,8 @@ And now to tie it all together. Meet `generation`, the longest bit of code in th
] buffer:preserve ;
~~~
The last bit is a helper. It takes a number of generations and displays the state, then runs a `generation`.
The last bit is a helper. It takes a number of generations and displays
the state, then runs a `generation`.
~~~
:generations (n-)

View file

@ -53,7 +53,7 @@ input.
[ ASCII:SPACE eq? ] tri or or ;
:s:get (a-)
buffer:set [ c:get [ buffer:add ] [ eot? ] bi ] until
buffer:set [ c:get [ buffer:add ] [ eot? ] bi ] until
buffer:get drop ;
:read-request (-)
@ -199,15 +199,19 @@ And the code for Casket is done.
## Using Casket
Casket requires [Retro](http://forthworks.com/retro) and a Unix system with inetd.
Casket requires [Retro](http://forthworks.com/retro) and a Unix system
with inetd.
Install Retro and put the `casket.forth` somewhere. Then add a configuration line to your `/etc/inetd.conf`. I use:
Install Retro and put the `casket.forth` somewhere. Then add a
configuration line to your `/etc/inetd.conf`. I use:
http stream tcp nowait/6/30/2 casket /home/crc/servers/casket.forth
Restart inetd.
Edit the `WEBROOT` in `casket.forth` to point to your web directory. Then go to the web directory and create a directory for each domain. E.g.,
Edit the `WEBROOT` in `casket.forth` to point to your web directory.
Then go to the web directory and create a directory for each domain.
E.g.,
/home/crc/www/casket.forthworks.com
@ -222,7 +226,9 @@ Put your `index.html` and other files here and try accessing your website.
## Real World Uses
Casket has been in use since the second half of 2018 serving a number of small websites. It's also used to host the Casket project page you are looking at.
Casket has been in use since the second half of 2018 serving a number of
small websites. It's also used to host the Casket project page you are
looking at.
---

View file

@ -2,11 +2,15 @@
## Description
This implements a function that takes an initial value and constructs a new function that returns the value before incrementing the stored value by 1.
This implements a function that takes an initial value and constructs a
new function that returns the value before incrementing the stored value
by 1.
So, given an initial value of 1, the first time the function is called, 1 is returned. The second, 2, and so on.
So, given an initial value of 1, the first time the function is called,
1 is returned. The second, 2, and so on.
In traditional Forth, this would be done using a CREATE/DOES> construct. RETRO allows for something similar using the `does` combinator.
In traditional Forth, this would be done using a CREATE/DOES> construct.
RETRO allows for something similar using the `does` combinator.
An example in a traditional Forth:
@ -18,19 +22,24 @@ In RETRO, we could begin by rewriting this using the RETRO words:
:acc (ns-)
d:create , [ dup push fetch n:inc pop store ] does ;
The `dup push ... pop` pattern is the `sip` combinator, so we can simplify it:
The `dup push ... pop` pattern is the `sip` combinator, so we can
simplify it:
:acc (ns-)
d:create , [ [ fetch n:inc ] sip store ] does ;
This is better, but not quite done. RETRO has a `v:inc` for incrementing variables, which would eliminate the n:inc and store. And a `bi` combinator to run two quotes against a value. So we could simplify yet again, resulting in:
This is better, but not quite done. RETRO has a `v:inc` for incrementing
variables, which would eliminate the n:inc and store. And a `bi`
combinator to run two quotes against a value. So we could simplify yet
again, resulting in:
~~~
:acc (ns-)
d:create , [ [ fetch ] [ v:inc ] bi ] does ;
~~~
This removes the primitive stack shuffling, and leaves something that expresses the intent more clearly.
This removes the primitive stack shuffling, and leaves something that
expresses the intent more clearly.
Finally, here's a little test case:

View file

@ -5,17 +5,30 @@ Updated for RETRO 12 by Charles Childers, 2018
## Description
This vocabulary provides support for testing code in a clean, predicatable manner.
This vocabulary provides support for testing code in a clean,
predicatable manner.
Assertion predicates first check the stack for underflow; if the stack is deep enough, their embedded predicates are applied; if not, the assertion fails.
Assertion predicates first check the stack for underflow; if the stack
is deep enough, their embedded predicates are applied; if not, the
assertion fails.
The result of each assertion - including the underflow check - is ANDed with the assertionFlag which can then be tested after the containing thread has finished executing; this is handled by the .assertion word class.
The result of each assertion - including the underflow check - is ANDed
with the assertionFlag which can then be tested after the containing
thread has finished executing; this is handled by the .assertion word
class.
For custom behaviour, revector preCond and/or postCond; by default the pre-condition is an effective nop while the post-condition simply prints 'Success' or 'Failure'.
For custom behaviour, revector preCond and/or postCond; by default the
pre-condition is an effective nop while the post-condition simply prints
'Success' or 'Failure'.
Given that each assertion predicate mutates assertionFlag, use of the word class `class:assertion` is encouraged; this resets the `assertionFlag` before execution and push its final value to the stack before calling postCond when the thread exits.
Given that each assertion predicate mutates assertionFlag, use of the
word class `class:assertion` is encouraged; this resets the
`assertionFlag` before execution and push its final value to the stack
before calling postCond when the thread exits.
NOTE: For simplicity of implementation, failure within a word of class `class:assertion` will not result in immediate termination; instead, the false value of `assertionFlag` is left to propagate.
NOTE: For simplicity of implementation, failure within a word of class
`class:assertion` will not result in immediate termination; instead, the
false value of `assertionFlag` is left to propagate.
## Code & Commentary
@ -158,7 +171,7 @@ These are from Hooks.forth:
| | | assertions |
+-----------------+-----+-----------------------+
| assertion | - | Change the class of a |
| | | function to |
| | | function to |
| | | class:asssertion |
+-----------------+-----+-----------------------+

View file

@ -2,13 +2,17 @@
## Description
This implements a means of encoding floating point values into signed integer cells. The technique is described in the paper titled "Encoding floating point numbers to shorter integers" by Kiyoshi Yoneda and Charles Childers.
This implements a means of encoding floating point values into signed
integer cells. The technique is described in the paper titled "Encoding
floating point numbers to shorter integers" by Kiyoshi Yoneda and
Charles Childers.
This will extend the `f:` vocabulary and adds a new `u:` vocabulary.
## Code & Commentary
Define some constants. The range is slightly reduced from the standard integer range as the smallest value is used for NaN.
Define some constants. The range is slightly reduced from the standard
integer range as the smallest value is used for NaN.
~~~
n:MAX n:dec 'u:MAX const

View file

@ -79,7 +79,8 @@ Given that, making a request is simply:
~~~
:make-request
@Params dup s:length @Host @Request
'POST_%s_HTTP/1.1\r\nHost:_%s\r\nContent-Type:_text/plain\r\nContent-Length:_%n\r\n\r\n%s\r\n s:format @Socket socket:send drop-pair ;
'POST_%s_HTTP/1.1\r\nHost:_%s\r\nContent-Type:_text/plain\r\nContent-Length:_%n\r\n\r\n%s\r\n
s:format @Socket socket:send drop-pair ;
~~~
Moving on to reading the body, this is just reading bytes and shoving

View file

@ -4,23 +4,30 @@
December: Palindromic numbers
Palindromic Numbers: The programming challenge for the Saturday, Dec. 19 Silicon Valley Forth Interest Group meeting. Numbers the same forward and backward as for RADAR but with numbers. Such as 88 and 666 and 12321.
Palindromic Numbers: The programming challenge for the Saturday, Dec. 19
Silicon Valley Forth Interest Group meeting. Numbers the same forward
and backward as for RADAR but with numbers. Such as 88 and 666 and
12321.
Program a generator or a filter to find all palindromic integers from 1 (yes, it is) to 99999. Please confirm your interest to Bill Ragsdale, bill@billragsdale.cc
Program a generator or a filter to find all palindromic integers from
1 (yes, it is) to 99999. Please confirm your interest to Bill Ragsdale,
bill@billragsdale.cc
## Code & Commentary
Well this is really easy. I begin by creating an array of potential values.
Well this is really easy. I begin by creating an array of potential
values.
~~~
#100000 [ I n:inc , ]
#100000 [ I n:inc , ]
'Potentials d:create over , indexed-times
~~~
Then a simple `palindrome?` word to convert the number to a string and return a flag indicating if it's a palindrome.
Then a simple `palindrome?` word to convert the number to a string and
return a flag indicating if it's a palindrome.
~~~
:palindrome? n:to-string dup s:reverse s:eq? ;
:palindrome? n:to-string dup s:reverse s:eq? ;
~~~
Use `palindrome?` to filter out invalid values.
@ -39,13 +46,18 @@ And finally, display the palindromes.
*Numeric Bases*
While Retro only supports decimal values by default, if you have extended `n:to-string` to support a `Base`, this will still work with other bases.
While Retro only supports decimal values by default, if you have
extended `n:to-string` to support a `Base`, this will still work with
other bases.
*Memory Use*
In my tests, this isn't memory efficient, as I'm keeping both the list of potentials and the results in memory, so it ends up consuming about 101k memory locations. If the results don't need to be kept, a much smaller solution would look like:
In my tests, this isn't memory efficient, as I'm keeping both the list
of potentials and the results in memory, so it ends up consuming about
101k memory locations. If the results don't need to be kept, a much
smaller solution would look like:
:palindrome? n:to-string dup s:reverse s:eq? ;
:palindrome? n:to-string dup s:reverse s:eq? ;
:value I n:inc dup ;
:process [ n:put nl ] &drop choose ;