examples: shorten line lengths
FossilOrigin-Name: a7e5fe4c71047a01a833ce31583ef5597f3f0235c5a2fab90e55f07510bc0bf5
This commit is contained in:
parent
45a1619f9e
commit
4c53181624
7 changed files with 112 additions and 45 deletions
|
@ -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-)
|
||||
|
|
|
@ -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.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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 |
|
||||
+-----------------+-----+-----------------------+
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ;
|
||||
|
||||
|
|
Loading…
Reference in a new issue