On this page:
2.1 Overview
2.2 Installation
2.3 Usage
2.4 Flowing with the Flow
2.4.1 Dr  Racket
2.4.2 Vim/  Emacs
2.4.2.1 Keybindings
2.4.2.2 Indentation
2.5 Relationship to the Threading Macro

2 Introduction and Usage

    2.1 Overview

    2.2 Installation

    2.3 Usage

    2.4 Flowing with the Flow

      2.4.1 DrRacket

      2.4.2 Vim/Emacs

        2.4.2.1 Keybindings

        2.4.2.2 Indentation

    2.5 Relationship to the Threading Macro

2.1 Overview

One way to structure computations – the one we typically employ when writing functions in Racket or another programming language – is as a flowchart, with arrows representing transitions of control, indicating the sequence in which actions are performed. Aside from the implied ordering, the actions are independent of one another and could be anything at all. Another way – provided by the present module – is to structure computations as a fluid flow, like a flow of energy, electricity passing through a circuit, streams flowing around rocks. Here, arrows represent that actions feed into one another.

The former way is often necessary when writing functions at a low level, where the devil is in the details. But once these functional building blocks are available, the latter model is often more appropriate, allowing us to compose functions at a high level to derive complex and robust functional pipelines from simple components with a minimum of repetition and boilerplate, engendering effortless clarity. The facilities in the present module allow you to employ this flow-oriented model in any source program.

2.2 Installation

Qi is a hosted language on the Racket platform. If you don’t already have Racket installed, you will need to install it. Then, install Qi at the command line using:

raco pkg install qi

Qi is designed to be used in tandem with a host language, such as Racket itself. To use it in a Racket module, simply (require qi).

2.3 Usage

Qi may be used in normal (e.g. Racket) code by employing an appropriate interface form. These forms embed the Qi language into the host language, that is, they allow you to use Qi anywhere in your program, and provide shorthands for common cases.

Since some of the forms use and favor unicode characters (while also providing plain-English aliases), see Flowing with the Flow for tips on entering these characters. Otherwise, if you’re all set, head on over to the tutorial.

> (require qi)
> (map ( (~> sqr add1)) (list 1 2 3))

'(2 5 10)

> (filter ( (< 5 _ 10)) (list 3 7 9 12))

'(7 9)

> (~> (3 4) (>< sqr) +)

25

> (switch (2 3)
    [> -]
    [< +])

5

> (define-flow root-mean-square
    (~>  (>< sqr) (-< + count) / sqrt))
> (root-mean-square (range 10))

5.338539126015656

2.4 Flowing with the Flow

If your code flows but you don’t, then we’re only halfway there. This section will cover some UX considerations related to programming in Qi, so that expressing flows in code is just a thought away.

The main thing is, you want to ensure that these forms have convenient keybindings:

~>

-<

Now, it isn’t just about being able to enter them, but being able to enter them without effort. This makes a difference, because having convenient keybindings for Qi is less about entering unicode conveniently than it is about expressing ideas economically, just as having evocative symbols in Qi is less about brevity and more about appealing to the intuition. After all, as the old writer’s adage goes, "show, don’t tell."

Some specific suggestions are included below for commonly used editors.

2.4.1 DrRacket

Stephen De Gabrielle created a quickscript for convenient entry of Qi forms: Qi Quickscripts. This option is based on using keyboard shortcuts to enter exactly the form you need.

Laurent Orseau’s Quickscript Extra library includes the complete-word script that allows you to define shorthands that expand into pre-written templates (e.g. ( \|), with \| indicating the cursor position), and includes some Qi templates with defaults that you could customize further. This option is based on short textual aliases with a common keyboard shortcut.

There are also a few general unicode entry options, including a quickscript for unicode entry in DrRacket, and The Unicoder by William Hatch for system-wide unicode entry. While these options are useful and recommended, they are not a substitute for the Qi-specific options above but a complement to them.

Use any combination of the above that would help you express yourself economically and fluently.

2.4.2 Vim/Emacs
2.4.2.1 Keybindings

For Vim and Emacs Evil users, here are suggested keybindings for use in insert mode:

Form

 

Keybinding

 

C-;

~>

 

C->

-<

 

C-<

 

C-v

 

C-V

 

C-=

For vanilla Emacs users, I don’t have specific suggestions since usage patterns vary so widely. But you may want to define a custom input method for use with Qi (i.e. don’t rely on the LaTeX input method, which is too general, and therefore isn’t fast), or possibly use a Hydra.

2.4.2.2 Indentation

In Racket Mode for Emacs, use the following config to indent Qi forms correctly:

(put 'switch 'racket-indent-function 1)
(put 'switch-lambda 'racket-indent-function 1)
(put 'on 'racket-indent-function 1)
(put 'π 'racket-indent-function 1)
(put 'try 'racket-indent-function 1)

2.5 Relationship to the Threading Macro

The usual threading macro in Threading Macros is a purely syntactic transformation that does not make any assumptions about the expressions being threaded through, so that it works out of the box for threading values through both functions as well as macros. On the other hand, Qi is primarily oriented around functions, and flows are expected to be function-valued. Threading values through macros using Qi requires special handling.

In the most common case where you are threading functions, Qi’s threading form ~> is a more general version, and almost drop-in alternative, to the usual threading macro. You might consider migrating to Qi if you need to thread more than one argument or would like to make more pervasive use of flow-oriented reasoning. To do so, the only change that would be needed is to wrap the input argument in parentheses. This is necessary in order to be unambiguous since Qi’s threading form can thread more than one argument.

For macros, we cannot use them naively as flows because macros expect all of their "arguments" to be provided syntactically at compile time – meaning that the number of arguments must be known at compile time. This is not in general possible with Qi since flows may consume and produce an arbitrary number of values, and this number is only determined at runtime. Depending on what you are trying to do, however, there are many ways in which you still can treat macros as flows in Qi – from simple escapes into Racket to more structured approaches including writing a Qi dialect.

The threading library also provides numerous shorthands for common cases, many of which don’t have equivalents in Qi – if you’d like to have these, please create an issue on the source repo to register your interest.