Hi Phil,

It is OK to do this as long as the intention is clear. Usually this
occurs in code which almost fits the pipeline pattern; there is a
parameter passed between quotations that is some kind of accumulator,
but other values needs to be provided too.

Sometimes this type of trick can obfuscate things without offering any
clear benefit though. Sometimes using 'keep' and 'dip' is better even
if the pattern can technically be expressed otherwise. This is all
very subjective.

I use this idiom all the time; it has effect ( tuple a-foo a-bar -- tuple ):

[ >>foo ] [ >>bar ] bi*

For another example look at the (compile) word:

: (compile) ( word -- )
    '[
        _ {
            [ start ]
            [ frontend ]
            [ backend ]
            [ finish ]
        } cleave
    ] with-return ;

the start word emits an IR, and the other words, frontend, backend and
finish, take an IR as input. All but finish also leave a new IR as
output. The word is "cleaved" so that each pass also receives the word
as well as the IR.

Some people might say this is stretching it but I think this is a
legitimate usage of cleave.

A similar situation also occurs with sequence combinators, by the way.
For example, if we didn't have 'reduce', you'd implement 'sum' as

: sum ( seq -- n ) 0 swap [ + ] each ;

Here + receives the previous tally as well as the next element on each
iteration. Of course, 'reduce' exists and its implemented as 'swapd
each'.

As an aside: a closely-related concept from static type theory is row
polymorphism. Suppose we had a hypothetical statically-typed Factor
dialect. We'd then say that 'each' is row-polymorphic because we can
give it a formal type signature:

forall A. forall a. A [a] (A a -> A) -> A

Where A is a 'row type' representing the rest of the stack, and 'a' is
a value type. The cleave and spread combinators can also be considered
to be row-polymorphic, because the quotations given can manipulate the
entire stack, and there are ways to formalize this with static types.
Things get complicated -- giving bi@ a static type that allows for the
full generality of Factor's dynamically-typed bi@ requires
intersection types.

Pervasive row polymorphism is an an interesting property of
stack-based concatenative languages, and one of the distinguishing
features of this paradigm.

Slava

On Thu, Apr 2, 2009 at 7:33 AM, Phil Dawes <[email protected]> wrote:
> Hi All,
>
> Factor style question: Is it ok to use spread combinators in places
> where subsequent quots use results from the previous ones? I like the
> symmetry it brings:
>
> (fictitious example:)
>
> : lop-off-back ( seq start -- seq' )
>   1+ head ;
>
> : lop-off-front ( seq len -- seq' )
>   short tail* ;
>
> : window ( seq start window-width -- subseq )
>     [ lop-off-front ] [ lop-off-back ] bi* ;
>
> vs
>
> : window ( seq start window-width -- subseq )
>     [ lop-off-front ] dip lop-off-back ;
>
> but obviously it wouldn't work if the quots weren't executed sequentially.
>
> What do you think?
>
> Cheers,
>
> Phil
>
>
> ------------------------------------------------------------------------------
> _______________________________________________
> Factor-talk mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/factor-talk
>

------------------------------------------------------------------------------
_______________________________________________
Factor-talk mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/factor-talk

Reply via email to