Hi all,

The first new feature is a couple of new looping combinators for the
kernel vocabulary.

One interesting thing about concatenative languages is the relative
ease with which you can work with multiple return values. This allows
you to write 'modifiers'. Suppose you have two words, foo, and bar,
with effect ( x y z -- ). You can write a word 'modify' with effect (
x y z -- x' y' z' ), and now you have four variations:

foo
bar
modify foo
modify bar

Clever usage of this allows you to express M*N variants of an
operation with only M+N words. One example is the 'short' word in the
sequences vocabulary:

"Hello world" 5 head => "Hello"
"Hello world" 5 short head => "Hello"
"Hi" 5 head => error
"Hi" 5 short head => "Hi"

Another example is the new 'do' word I just added. We've had a while
combinator for quite some time,

[ P ] [ Q ] [ T ] while

It behaves like a C while loop; if the predicate returns false, the
body never executes. Using 'do', you can force the body to execute at
least once:

[ P ] [ Q ] [ T ] do while

'do' is defined as follows:

: do over 3dip ;

There is a new combinator, until:

[ P ] [ Q ] [ T ] until == [ P not ] [ Q ] [ T ] while

It can also be used with do. This means we get 'do until' and 'do
while' without having to implement anything new (the definition of do
is trivial). Try doing that in Lisp or Haskell!

The second new feature is a new syntax for defining locals. Inside
your :: word or lambda, you can now do this:

... :> foo
... foo ...

:> defines a local whose value is the top of the stack, for the
duration of the innermost lexical scope. It is equivalent to the
following:

[let | foo [ ] ... foo ... ]

Note that lambdas and lets can be expressed in terms of :>

[| a b c | ... ]
[ :> c :> b :> a ... ]

[let | a [ X ] b [ Y ] | ... ]
X :> a Y :> b ... ! assuming Y does not reference 'b' from an outer scope

but it is considerably more concise for the common case where you word
only needs to define one local. The idea for this syntax has been at
the back of my mind for quite some time, but only a few days ago did
the need for it arise. I wanted to rewrite parts of locals for
improved compile-time performance; the main problem with the old
implementation was the translation for [let;

[let | a [ X ] | Y ]

would translate to the following

X [| a | Y ] call

However, the subsequent closure conversion step would introduce a lot
of nested quotations with currying, and the result was some rather
complex code which took a lot of work for the compiler to boil down to
efficient stack code. The new translation of [let in terms of :> makes
the path from locals code to machine code more direct. There is no
performance difference in the generated code, but compile time has
improved. The most drastic speedup has been with the peg.javascript
vocabulary, which would formerly take just over 3 minutes to load, and
now it loads in under 2 minutes. The code generated by the PEG library
makes heavy use of locals and inlining, so compile time performance
really matters here. There is still a lot of room for improvement
there, of course, but this was a big jump.

Slava

------------------------------------------------------------------------------
SF.Net email is Sponsored by MIX09, March 18-20, 2009 in Las Vegas, Nevada.
The future of the web can't happen without you.  Join us at MIX09 to help
pave the way to the Next Web now. Learn more and register at
http://ad.doubleclick.net/clk;208669438;13503038;i?http://2009.visitmix.com/
_______________________________________________
Factor-talk mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/factor-talk

Reply via email to