Together with Einar, I’ve been deeply immersed in domain analysis for our upcoming trading language for the past month – i.e., analyzing the domain of trading. One of the crucial things we’ve been focusing on, is the rich vocabulary you are likely to hear when listening to traders working together. Their vocabulary captures how trading ideas are transmitted between humans. As the philosopher Gadamer might have argued, we think in words. And traders have invested time and effort into learning “the trading words”, because with language comes the knowledge and vice versa.
We want to capitalize on their investment by exposing the raw computing power of modern computers using a familiar language. If our target group were mathematicians, the language and notation of choice would be + - / * f(x), and all the other weird symbols we learned in school (and many we didn’t learn). If our target group were programmers, formal languages like Java or C++ would be an good starting point for inventing a new variant for trading.
But our future users are traders first, then a little bit of mathematician, then programmers as a distant third. With this in mind, we have done some serious consideration into using natural language as a basis for expressing trading rules. As part of this consideration, I did a (perhaps too short, but very enlightening) survey of the state of the art of using English as a programming language. I’m sharing my findings here, since they might be of broader interest.
Background
Let me give you a very concrete idea of what we want: Our motivation for using English as a programming language is to be able to support trading rules written almost exactly like regular English sentences, e.g.
if seeing more than 3 news headlines
from distinct sources
containing 'Hurricane' and 'US'
within 1 minute:
flatten positions
Again, our users (c.f. Takuya) are domain experts, but not programmers. They will mostly likely be reading code more often than they write it. They will not be coding every day, only now and again. They’re usually not interested in spending all that much time getting into that specific frame of mind for solving complex problems that regular programmers love so much (you know what I mean only too well, admit it).
As anybody will tell you, the English language is rather unbounded and pretty rife with ambiguities. I’ve come across a wide range of efforts to manage this problem, and I’ll share some highlights from the various efforts here.
Natural Language Programming
One of the major selling points of the Natural Language Programming technique is the ability to write technical documents shared by computers and humans. The technique exposes to its user an iterative process whereby rules for turning sentences into code are formulated. This multi-step process goes as follows:
- Define your taxonomy of concepts – i.e. names of interest in your domain. In our case: prices, instruments, pips, pricing, trends, support, resistance, etc.
- Define top-level sentences using said concepts, e.g. define support if bottom is at same level within X minutes.
- Define top-level sentences in terms of sequences of other sentences which also include said concepts.
- When you reach the most primitive sentences, you define a mapping from these to code in an (any) existing programming language, somewhat like a template system.
- Repeat until there is a mapping for all paths from the top-level sentences to code.
The example provided at Wikipedia is more detailed:
If U_ is 'smc01-control', then do the following.
Define surface weights Alpha as "[0.5, 0.5]". Initialise matrix Phi
as a 'unit matrix'.
Define J as the 'inertia matrix' of Spc01.
Compute matrix J2 as the inverse of J.
Compute position velocity error Ve and angular velocity error Oe
from dynamical state X, guidance reference Xnow.
Define the joint sliding surface G2 from the position velocity error
Ve and angular velocity error Oe using the surface weights Alpha.
Compute the smoothed sign function SG2 from the joint sliding
surface G2 with sign threshold 0.01.
Compute special dynamical force F from dynamical state X and
surface weights Alpha.
Compute control torque T and control force U from matrix J2, surface
weights Alpha, special dynamical force F , smoothed sign function SG2.
Finish conditional actions.
The technique is supported by a system called System English. There is a page listing a few more examples, all of them in the style of the example above.
I must admit that this is a rather intriguing technique. My present reservation is that all the examples are rather verbose, and a dreary read. The documents (i.e., programs) are very repetitive, with a lot of sentences starting with either define
or compute
. This might be perfectly fine for technical documentation. I’ll not make any hasty judgments about its applicability to trading before actually having tested it for our domain, though.
Maude
It might come as a surprise to find Maude on this list, but let me explain why I included it. Maude is a language for equational and rewriting logic specification and programming. That sounds scary, but let’s focus on the parts of Maude which allow you build sentence fragments, the operators.
op add _ to _ : Num List -> List
This defines the operator (sentence fragment) add to
. Assuming list is a list, the definition allows you to write
add 1 to list
which (provided that the add to
operator does its job correctly), will add 1 to a list of numbers.
Since you are free to define any operator, you can also start defining your own mathematical operators
op _ + _ : Num Num -> Num
op _ * _ : Num Num -> Num
This allows you to write expressions a * b + c
, as you might expect. There is one crucial point here, however. The precedence of the operators are not fixed. You are free to define these yourself. This means that the expression just given, will be ambiguous. It’s not (yet) defined whether it should be taken to mean (a * b) + c
or a * (b + c)
. As you might guess, these are wrinkles that are rather important to iron out.
Maude comes to the rescue with a precedence annotation:
op _ + _ : Num Num -> Num [prec 35]
op _ * _ : Num Num -> Num [prec 25]
Think of this as a little bit of grammatic chemistry: the operator with the lower precedence will bind stronger to its arguments. With the precedence annotation in place, the expression a * b + c
is now always interpreted as (a * b) + c
, because *
binds stronger than ’+’.
The operator +
brings another ambiguity to the table: associativity. When writing a + b + c
, should it be taken to mean (a + b) + c
or a + (b + c)
. The precedence cannot help us, since it will always be the same for the two “competing” pluses (plus competing against itself). As it happens, for the +
operator, it really doesn’t matter. Both alternatives are the same. In mathematics, an operator with this property is called associative. Maude provides the [assoc]
annotation for marking an operator with this property. Commutativity (that x op y
is the same as y op x
) is marked by [comm]
.
However, there may be cases with an operator is not associative, such as the divide operator. The Maude 2.0 Primer suggests that vs
is also such an operator:
op _ vs _ Player Player -> Player [comm]
Let’s assume we’re back in the early 90s and that the following battle is at hand: Chun-Li vs Ryu vs Ken. If we read this is as (Chun-Li vs Ryu) vs Ken the winner of Chun-Li and Ryu will face Ken. In the interpretation Chun-Li vs (Ryu vs Ken), Chun-Li will face the winner of Ken and Ryu. Clearly not the same meaning.
Again, Maude comes to the rescue with an annotation: gather
. Gather takes a number of flags equal to the number of arguments for your operator (in this case two). Each gather flag tells us something about the precedence of the operator found at argument. A flag may be either of e
(strictly less), E
(less or equal), &
(any). Confuzzled? Let’s try it out.
op _ vs _ Player Player -> Player [comm] [prec 33] [gather(e E)]
This defines that the first argument to vs
must be of precedence strictly less than that of vs
. Since the precedence of vs
can never be strictly less than itself; (Chun-Li vs Ryu) vs Ken is therefore not allowed – the only valid interpretation left is Chun-Li vs (Ryu vs Ken). With that ambiguity out of the way, we can proceed to the real action. Fight!
Clearly, these mechanisms make Maude very expressive. In practice, Maude allows programmers to fairly freely define their own language with a rather natural looking syntax for any library they might want to design. The downside is that mastering Maude’s disambiguation mechanics is an art unto its own.
Action Semantics
Another little language with a very English-like syntax I’ve come across in previous travels is that of Peter D. Mosses’ formalism for defining semantics for programming languages. I.e., a “programming language” for defining the meaning of programming languages. The following, which tells how the identifier I
is to be evaluated, should provide some flavor:
evaluate I = give the expressible bound to I
or
enact the abstraction bound to I
While not exactly in widespread use, it has been used to define semantics for some non-trivial languages, such as the dynamic semantics for Pascal.
Mosses and colleagues have written research tools to fully generate compilers based on language definitions in the action semantics formalism. The value proposition of Action Semantics is pretty clear: it allows you define your programming language at a high level, and then generate language tools such as interpreters and compilers (almost) for free – provided your language fits into the AS formalism.
Metafor
Metafor was a research prototype of a user interface for visualizing interactively typed stories as code (not available for general consumption). The idea was that users type English sentences describing their domain. Metafor then continually analyzes the typed story and maintains a “Python-view”. The Python view contains the structure of the code.
For example, when the user types the code:
There is a bar with a bartender who makes drinks.
Metafor would generate the following code:
class bar:
the_bartender = bartender()
class bartender:
def make(drink): pass
The “translation” from English to code is done using a slew of natural language processing tricks, including a natural language parser and a large database of English “common sense” sentences from which “knowledge” about the various words is extracted.
As far as I know, the system was only ever able to generate the outline of your program. The larger, and perhaps more interesting, problem of writing program logic in English is still left as an exercise to the reader.
An improved version of Metafor be useful for doing structural/architectural design of code and classes, but the project seems discontinued. Fortunately, some of the appealing properties of Metafor are available in the Inform-series of adventure game/interactive fiction-creators.
Inform 7
The Inform system might be seen as a continuation of the good old Infocom-style of games, but on steroids and done really well. Inform is a design system for interactive fiction based on natural language. It comes with an “IDE” for developing interactive fiction, or text-based adventures, if you will.
You can easily define locations and entities:
The wood-slatted crate is in the Gazebo.
The crate is a container.
Mr Jones wears a top hat.
The crate contains a croquet mallet.
In the nomenclature of Inform, these are assertions. A number of built-in verbs are used to state assertions: to be, to have, to carry, to wear, to contain and to support. It is possible for users to extend this set of verbs.
Based on the above sentences, the system will create the objects ‘crate’, 'Mr Jones’ and 'croquet mallet’. It will even place the croquet mallet inside the crate, so that the player must open it to find the mallet.
All in all, the system seems very well crafted and is the most impressive example of natural language programming I have seen to date. Again, I have no practical experience using it, so I cannot offer any advice on how expressive such and approach be might be for areas other than interactive fiction.
AppleScript
Perhaps the English-like language with the most widespread use, is that of AppleScript, as found on all Apple computers today. AppleScript was designed in the early 90s and is a descendent of the HyperCard hype of the late 80s. According to its creators, AppleScript is aimed at “casual programmers”. This includes programmers of all experience levels who are primarily out to solve problems, not write programs.
A simple AppleScript program for manipulating Excel:
tell application ‘‘ Excel ’’ on machine x
put 3.14 into cell 1 of row 2 of window 1
end
Another script for doing a bit of cut-n-pasting:
copy the name of the first window of application ‘‘ Excel ’’
to the end of the first paragraph of app ‘‘ Scriptable Text Editor ’’
I came across this excellent report: AppleScript. William R. Cook, University of Texas at Austin With contributions from Warren Harris, Kurt Piersol, Dave Curbow, Donn Denman, Edmund Lai, Ron Lichty, Larry Tesler, Mitchell Gass & Donald Olson September 29, 2006.
This report is a really interesting read to anyone who considers using English as a programming language. To set the stage, let’s start with their conclusion:
Many of the current problems in AppleScript can be traced to the use of syntax based on natural language; however, the ability to create pluggable dialects may provide a solution in the future, by creating a new syntax based on conventional programming languages.
The English-like syntax, initially touted as a great way to capture the minds and souls of non-programmer and programmer alike, turned out to be the major Achilles heel of the language. Hmmm.
In the discussion, the authors go into a bit more detail:
The experiment in designing a language that resembled natural languages (English and Japanese) was not successful. It was assume that scripts should be presented in “natural language” so that average people could read and write them. […] In the end the syntactic variations and flexibility did more to confuse programmers than to help them out. The main problem is that AppleScript only appears to be a natural language. In fact is an artificial language, like any other programming language. […] It is easy to read AppleScript, but quite hard to write it.
When writing programs or scripts, users prefer a more conventional programming language structure. Later versions of AppleScript dropped support for dialects. In hindsight, we believe that AppleScript should have adopted the Professional Dialect that was developed but never shipped.
So, the main problem seems to stem from AppleScript not providing “English as we know it”. It has a surface syntax which reads pretty much like English. However, when trying express yourself in AppleScript, most of the grammar rules, idioms, proverbs and personal style you are accustomed to, is simply not there. Instead, you are forced to mould your ideas into a sort of Pidgin English, the AppleScript English, which doesn’t really behave like you expect. And the worst thing programmers know is when things don’t behave as they expect.
In retrospect, this might not come as a surprise. Many, if not most, programming languages are designed to be somewhat syntactically and grammatically minimal. There is often only one, or at most a few, ways of stating the basic things. Based on a set of core language constructs, you can build successively larger programs. But the set of core constructs behave rather simply and predictably. (Yes, Perl is a rather famous example of the opposite.)
The Osmosian Order
Osmosian Order is not as much a project as it appears to be a movement. According to their manifesto:
The Osmosian Order of Plain English Programmers is a group of like-minded developers and educators dedicated to the rescue of computer science from the pervasive fog of confusion engulfing it today.
They even have a plan:
Our initial goal is to see Plain English (and other natural-language variants, such as Plain Spanish and Plain German) adopted as de facto standard languages.
To that end, they have (allegedly) written a compiler and development environment for programming using Plain English. An example Plan English program is given below:
To create the background:
Draw the screen's box with the white color.
Loop.
Pick a spot anywhere in the screen's box.
Pick a color between the lightest gray color and the white color.
Dab the color on the spot.
If a counter is past 80000, break.
If the counter is evenly divisible by 1000, refresh the screen.
Repeat.
Extract the background given the screen's box.
\or Create the background from the screen.
Or something.
To finish a work:
If the work is nil, exit.
If the work is finished, exit.
Create a picture given the work's URL.
If the picture is nil, exit.
Resize the picture to 5-1/2 inches by 5-1/2 inches.
Center the picture in the screen's box.
Draw the background.
Draw the picture.
Loop.
Pick a spot anywhere near the picture's box.
Mix a color given the spot.
Dab the color on the spot.
If a counter is past 20000, break.
Repeat.
Extract the work's painting given the picture's box.
Destroy the picture.
Reputedly, The Order provides a fast compiler which is able to turn the stylized English above into an executable Windows program. The compiler isn’t freely downloadable, but their web page says you can get it by e-mail.
Tentative conclusion
Using English as a programming language is definitely not a no-brainer. There are some hard trade-offs to be juggled.
My present thinking is that if the price of predictability is the cost of learning a new language, people with extensive scripting needs will pay it gladly. If this cost is kept low by providing a set of core language constructs already known from other programming languages, getting started with scripting becomes trivial. While the ultimate goal will always be do-what-I-mean (and not as I think or say) computers, an intermediate step seems to be where most computer literates have a working knowledge of scripting. As long as most scripting languages resemble each other, it’s sort of like knowing any one of the Scandinavian languages – you can easily get by in all of Scandinavia knowing just one of them.