minforth@gmx.net (minforth) writes:
Thanks. But it seems this is only the old 16-bit DOS version.
Looking at the Vierte Dimension 2/2024, which arrived this week, I
find another article about the new, 32-bit strongForth, and also the
link
https://www.stephan-becher.de/strongforth3/
DO you mean something like the below? The code stays the
same but it is possible to choose a different type of
variable (from BYTE to arbitrary precision).
On Thu, 25 Jul 2024 9:06:03 +0000, mhx wrote:
DO you mean something like the below? The code stays the
same but it is possible to choose a different type of
variable (from BYTE to arbitrary precision).
...
0-VALUE GLOCAL t0
LET SQRT(1/3): GLOCAL ti1
LET SQRT(1/3): GLOCAL ti2
...
LET t0=6*ti1*2^DOUBLE[I]:
LET ti1 = (SQRT(ti1*ti1+1)-1)/ti1:
LET ti2 = ti2/(SQRT(ti2*ti2+1)+1):
Thank you! Yes, something like that.
If I understand correctly, the intelligence is within LET
which decides which operator matches the type of the operands.
On Thu, 25 Jul 2024 9:06:03 +0000, mhx wrote:
LET t0=6*ti1*2^DOUBLE[I]:
I gather the (integer) 6 is autoconverted. Why not I as well?
If I understand correctly, the intelligence is within LET
which decides which operator matches the type of the operands.
Can you use global VALUEs (or even VARIABLEs) within LET?
Or does it only work with local types?
LET is not written in standard Forth. It is based on
Wil Baden's OPG (Operator Precedence Grammar), but there are
additions so that XOPG can be used as a SPICE expression
evaluator/compiler.
I am thinking on a much smaller scale i.e. unification of
operators for xVALUEs and xLOCALs. ANS Forth already has
overloaded TO but stops there.
+TO is a common extension.
On Thu, 25 Jul 2024 12:08:58 +0000, Anton Ertl wrote:
I am thinking on a much smaller scale i.e. unification of
operators for xVALUEs and xLOCALs. ANS Forth already has
overloaded TO but stops there.
+TO is a common extension.
Certainly. I have some array operations in mind, but they
are not relevant here. The principle is like
: INIT { a }
[[: a ;]] \ read counter
[[: 1 +to a ;]] ; \ increment counter
DEFER count IS count
DEFER read IS read
5 INIT
COUNT COUNT READ -> should give 7
[[: ;]] define closures, but unlike gforth's more flexible
flat closures, they capture simply all upvalues (here local a).
The code compiles unmodified for different types of a.
Incidentally, it compiles now with +TO, but realistically you
can't declare new 'op'TOs for too many different 'op' operators.
minforth@gmx.net (minforth) writes:
[[: ;]] define closures, but unlike gforth's more flexible
flat closures, they capture simply all upvalues (here local a).
Gforth's flag closures can be considered lower-level (they come out of implementation ideas in the Scheme community) and are easier to
implement, but emulating closures that capture outer locals is more cumbersome.
One other aspect is that in Gforth's closures the
programmer decides whether closures are allocated in the dictionary,
on the locals stack, on the heap, or elsewhere.
This raises the question of why you want to use closures for this
task. Why not use one of the object-oriented Forth packages, some of
which support value-flavoured fields (Mini-OOF2 among them AFAIK).
minforth@gmx.net (minforth) writes:
On Thu, 25 Jul 2024 12:08:58 +0000, Anton Ertl wrote:
I am thinking on a much smaller scale i.e. unification of
operators for xVALUEs and xLOCALs. ANS Forth already has
overloaded TO but stops there.
+TO is a common extension.
Certainly. I have some array operations in mind, but they
are not relevant here. The principle is like
: INIT { a }
[[: a ;]] \ read counter
[[: 1 +to a ;]] ; \ increment counter
DEFER count IS count
DEFER read IS read
5 INIT
COUNT COUNT READ -> should give 7
My guess is that three lines here should be
DEFER count
DEFER read
5 INIT IS count IS read
[[: ;]] define closures, but unlike gforth's more flexible
flat closures, they capture simply all upvalues (here local a).
Gforth's flag closures can be considered lower-level (they come out of >implementation ideas in the Scheme community) and are easier to
implement, but emulating closures that capture outer locals is more >cumbersome. One other aspect is that in Gforth's closures the
programmer decides whether closures are allocated in the dictionary,
on the locals stack, on the heap, or elsewhere. In the present case
the dictionary seems to be a good place, and one can write this
example as:
: init ( a -- )
align here >r , \ allocate a on the heap
r@ [n:d @ ;] \ read counter
[n:d 1 swap +! ;] \ increment counter;
DEFER count
DEFER read
5 INIT IS count IS read
count count read . \ prints "7 "
INIT uses pure-stack closures [n:d consumes a value (in this exampl,
the address of the cell containing A) from the stack at closure
creation time and pushes it on the stack at closure run-time. Look,
Ma, no locals:-).
However, this does not use value-flavoured stuff, because we have to
pass the address of A around, and then it's easier to use the >variable-flavoured words. However, if you prefer the value-flavoured
words, value-flavoured fields were recently added to Gforth and can be
used to do that:
begin-structure counter
value: counter-val
end-structure
: init ( a -- )
align here >r counter allot
r@ to counter-val
r@ [n:d counter-val ;]
[n:d 1 swap +to counter-val ;];
DEFER count
DEFER read
5 INIT IS count IS read
count count read . \ prints "7 "
However, you still have to deal with the address explicitly, which
becomes especially obvious in the counter closure.
This raises the question of why you want to use closures for this
task. Why not use one of the object-oriented Forth packages, some of
which support value-flavoured fields (Mini-OOF2 among them AFAIK).
The code compiles unmodified for different types of a.
Incidentally, it compiles now with +TO, but realistically you
can't declare new 'op'TOs for too many different 'op' operators.
This statement can be read in two different ways. I think there can
be too many, but Stephen Pelc may think otherwise:-).
- anton
Personnaly I hate TO and +TO, but if you decide to use them, you
could as well go all the way.
The standard suggests/specifies that operators such as TO behave as if
they parse. Ignore that for the moment and define
variable operator
: to 1 operator ! ; immediate
A child of VALUE is probably an immediate word that inspects OPERATOR
and compiles the fetch action if 0 or the store action if 1. This scheme
can
be extended to support a wide range of operators, such as +TO INCR DECR
and so on. MPE has used this scheme for several decades with no tech
support issues. If you really want to to be fussy and avoid the use of
the
"as if" rule for parsing, you can do something like (untested) the below
for TO. But why bother?
: to
1 operator ! ' execute
; immediate
111 value x x . 111 ok[..]
222 to cr .( Does TO parse? ) x x 222 = [if] .( No it doesn't!) [then]
Does TO parse? No it doesn't! ok
You could argue that it's not a standard program because it contains a deliberate ambiguous condition so a parsing TO would fail in some way
but it does demonstrate non-compliant behaviour.
1 value fv
222 to cr
fv
looks weird but probably works with a non-parsing TO i.e.
store 222 in fv.
TO stores an id as a message in a global variable which is
queried and reset by the next value.
It's a bit like in the old message-object vs object-message
discussion. Both have pros and cons.
5 value ix
55 (( ix )) stockprice
the runtime action of an xVALUE (even when
compiled)
involves to walk a type-specific operator chain (a large CASE construct
in VFX).
On Sat, 27 Jul 2024 15:35:55 +0000, Anton Ertl wrote:
minforth@gmx.net (minforth) writes:
[[: ;]] define closures, but unlike gforth's more flexible
flat closures, they capture simply all upvalues (here local a).
Gforth's flag closures can be considered lower-level (they come out of
implementation ideas in the Scheme community) and are easier to
implement, but emulating closures that capture outer locals is more
cumbersome.
In MF36 quotations already have read/write access to the locals of the
parent function. So closures became a simple by-product through
capturing
the parent's locals stack and injecting it at startup during closure
runtime. When the closure finishes, the captured stack is simply
updated.
I don't know if this would be good enough for a Lisp/Scheme programmer,
but it works for my needs. And look Ma, no garbage collection. :-)
One other aspect is that in Gforth's closures the
programmer decides whether closures are allocated in the dictionary,
on the locals stack, on the heap, or elsewhere.
In MF36 it is only the locals stack. AFAIU in other programming
languagues there are closures where the parent function can be seen as >constructor. IOW call the parent function twice and you get different >xts/addresses. From this perspective MF36 closures would perhaps only
qualify as 'half-closures'.
This raises the question of why you want to use closures for this
task. Why not use one of the object-oriented Forth packages, some of
which support value-flavoured fields (Mini-OOF2 among them AFAIK).
MF36 VALUEs and LOCALs are already built with method VTs. TO et al
just call the method in the correct method slot.
I don't know if this would be good enough for a Lisp/Scheme programmer,
but it works for my needs. And look Ma, no garbage collection. :-)
But then, with
| : INIT { a }
| [[: a ;]] \ read counter
| [[: 1 +to a ;]] ; \ increment counter
| DEFER count IS count
| DEFER read IS read
| 5 INIT
| COUNT COUNT READ -> should give 7
is A not gone after INIT is finished, and COUNT and READ will do ... interesting things?
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 504 |
Nodes: | 16 (2 / 14) |
Uptime: | 11:21:59 |
Calls: | 9,903 |
Calls today: | 12 |
Files: | 13,797 |
Messages: | 6,343,281 |
Posted today: | 6 |