On this page:

19 Pipelines

 (require (planet untyped/unlib/pipeline))

Pipelines allow a programmer to wrap procedure calls in one or more pieces of useful functionality. Pipelines are lists of stages, each of which performs some function and calls the next stage. The last stage calls the target procedure.

An example of the usefulness of this concept is request processing in a web application. The application may consist of a number of controller procedures, each of which serves a different page of HTML. Many of these procedures will have one or more bits of functionality in common:

Note that, while many of these functions will be common across many controllers, there will be occasions where one controller will need to do things differently from the others.

The tasks above can be implemented as stages in a request processing pipeline. A standard pipeline can be offered site-wide, and controllers can choose to customise it where appropriate by adding, removing or changing stages.


  > (define-stage (stage1 continue arg1 arg2 arg3)

      (printf "Entering ... ")

      (continue arg1 arg2 arg3))

  > (define-stage (stage2 continue arg1 arg2 arg3)

      (printf "continuing ... ")

      (continue arg1 arg2 arg3))

  > (define (target arg1 arg2 arg3)

      (printf "done.~n")

      (list arg1 arg2 arg3))

  > (call-with-pipeline (list stage1 stage2) target 1 2 3)

  Entering ... continuing ... done.

  (1 2 3)

Stages are named so they can be uniquely referred to when manipulating pipelines in this way. This has the added advantage that single stages can be extracted and run out of context with the rest of the pipeline.

More formally, given a target procedure:

     target : arg ... -> ans

a pipeline is a list of stages:

     pipeline : (listof stage)

where a stage is a name and a body procedure:

     stage : (struct symbol ((arg ... -> ans) arg ... -> ans))

The procedure in the stage takes the same arguments as target, plus a "continuation procedure" that is called to continue the pipeline. The arguments passed to the continuation procedure are passed on to the next stage, and so on to the target.

Any stage can abort the pipeline simply by failing to call the continuation procedure. It is also reasonable for stages to set up parameters, install exception handlers, change the arguments to subsequent stages and so on.





(name body))




  name : symbol?

  body : procedure?

A pipeline. The first argument to body procedure is always a continuation procedure that passes control to the next stage in the pipeline.

Stages take advantage of PLT’s structures/procedure masquerading functionality: they can be called directly as if they are procedures.

(define-stage (id arg ...) expr ...)

Shorthand syntax for make-stage that supplies id as the name of the stage. The form has support for rest arguments and PLT 4 optional and keyword arguments.

(call-with-pipeline pipeline target arg ...)  any

  pipeline : (listof stage?)

  target : procedure?

  arg : any

Calls target via the stages pipeline. The result returned is either the return value of target or that of the last stage invoked.

(find-stage pipeline name)  (U stage? #f)

  pipeline : (listof stage?)

  name : symbol?

Returns the appropriately named stage in pipeline or #f if the stage is not found.