Pipeline style

Suppose we wish to compose a sequence of functions A, B, C, D. In a concatenative language, you just write


In an applicative language, you'd write something like the following:

(D (C (B (A x))))

This looks "backwards", because one must read it from right to left; A is the first function to execute, then B, then C, then D. Haskell has an infix operator for function composition, so the excessive nesting is gone but the code still looks "backwards":

D . C . B . A

In the Factor community, we call such code "pipeline code".

Pipeline code is one of the simplest idioms in a stack language; you have a sequence of words, where each word takes a single value from the stack and leaves a new value there. Such words can be chained together much like commands in the Unix shell. For example, here is some Factor code:

"/etc/passwd" ascii file-lines
[ "#" head? not ] filter
[ ":" split first ] map

This is very similar to the following Unix shell script:

cat /etc/passwd | grep -v '^#' | sed -e 's/:.*//'

A variation on pipeline code can be found in the UI framework. Here, we are building a tree of gadgets, so it is not quite a pipeline: we create child gadgets, build them up, then add them to the parent using add-gadget ( parent child -- parent ). Here is an elaborate example:

USING: ui.gadgets.packs ui.gadgets.labels ui.gadgets.borders
ui.gadgets ui.gadgets.buttons ui.backend ui.render ui colors.constants
ui.pens.solid ;

    "Hello" <label> add-gadget
    "Click me" [ drop beep ] <border-button> add-gadget
        "A" <label>
            COLOR: red <solid> >>interior
        "B" <label>
            COLOR: green <solid> >>interior
        "C" <label>
            COLOR: blue <solid> >>interior
5 iota <border>
    COLOR: black <solid> >>boundary
"Test" open-window

Notice it reads almost like a declarative description, but really it is just stack code.

This revision created on Sat, 15 May 2010 10:56:37 by erg (fix example)