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
