The stack effect of many
inline combinators can have variable stack effects, depending on the effect of the quotation they call. For example, the quotation parameter to
each receives an element from the input sequence each time it is called, but it can also manipulate values on the stack below the element as long as it leaves the same number of elements on the stack. (This is how
reduce is implemented in terms of
each.) The stack effect of an
each expression thus depends on the stack effect of its input quotation:
USING: io sequences stack-checker ;
[ [ write ] each ] infer.
( x -- )
USING: sequences stack-checker ;
[ [ append ] each ] infer.
( x x -- x )
This feature is referred to as row polymorphism. Row-polymorphic combinators are declared by including row variables in their stack effect, which are indicated by names starting with
..:
IN: sequences : each ( ... seq quot: ( ... x -- ... ) -- ... )
Using the same variable name in both the inputs and outputs (in the above case of
each,
...) indicates that the number of additional inputs and outputs must be the same. Using different variable names indicates that they can be independent. In combinators with multiple quotation inputs, the number of inputs or outputs represented by a particular
.. name must match among all of the quotations. For example, the branches of
if* can take a different number of inputs from outputs, as long as they both have the same stack height. The true branch receives the test value as an added input. This is declared as follows:
IN: kernel : if* ( ..a ? true: ( ..a ? -- ..b ) false: ( ..a -- ..b ) -- ..b )
Stack effect variables can only occur as the first input or first output of a stack effect; names starting in
.. cause a syntax error if they occur elsewhere in the effect. For words that are not
inline, effect variables are currently ignored by the stack checker.