When I first circulated Groups16 for review as an illustration of programming methodology, several reviewers suggested that it might make a good instructional program -- provided it could be made easier for students to use.
Groups32, as presented so far, requires the user to learn a collection of command names, together with the parameters (and order) required for their use. As with similar research systems, there are actually only a handful of top-level commands in the system. (The others are useful mainly for those who wish to write programs to extend the system.) It is not unrealistic to use the system with a "command line" interface, but there is a learning curve involved, making casual use more difficult. Typing commands and their arguments is slow. Also, a more constrained type of input would decrease the need for error trapping.
I explored several methods to make these top-level commands more accessible and to ensure valid input. In one attempt, evoking a top level command provided prompts for parameters. In another, I presented the top-level commands in a menu -- clicking on a command initiated a prompt for input.
The approach I finally used, a "command completion" interface, appears to be the quickest and easiest to use. In this interface, the user is presented with a list of available commands:
CENTER CENTRALIZER CHART CONJ-CLS
COSETS EVALUATE GENERATE GROUP
HELP ISOMORPHISM LEFT MENU
NORMALIZER ORDERS PERMGRPS POWERS
QUIT RESULT RIGHT SEARCH
STOP SUBGROUPS TABLE
The user types enough letters of a command to distinguish it from the others. To generate a table, for example, the user needs only to type "T", since this is the only command that starts with T. To obtain a list of conjugacy classes, the user types "CON". The interface discards all letters typed beyond the bare minimum (so the user need not worry about mistyping subsequent characters). Once the interface identifies a command, it prints the rest of the command and prompts for any arguments needed to carry out its operation.
G1>> CONJ-CLS Group Number 8 { A } { B C } { D E F }
Typing "CON" distinguishes the CONJ-CLS command and asks for a group number.
Here is a sketch of how I implemented the interface:
The commands and information about them are put into a binary tree. Each node in the tree has a name field (for a string of a maximum size), the address of the node to the left, the address of the node to the right, and the execution address of the word used to carry out the command.
32 CONSTANT Max#Cmds
24 CONSTANT CmdSize
0 VALUE #Cmds
CmdSize CELL + CONSTANT EntrySize
Max#Cmds CONSTANT #Nodes
CREATE 'Tree1 #Nodes NodeSZ * ALLOT ALIGN
: Left ( n_addr -- l_addr ) SZ + @ ;
: Right ( n_addr -- r_addr )
SZ + 1 CELLS + @ ;
: Exec ( n_addr -- )
SZ + 2 CELLS + @ EXECUTE ;
: Left! ( x n_addr -- ) SZ + ! ;
: Right! ( x n_addr -- )
SZ + 1 CELLS + ! ;
: Exec! ( e_addr n_addr -- )
SZ + 2 CELLS + ! ;
: Name! ( $ n_addr -- ) DUP SZ BLANK $!! ;
: Leaf? ( n_addr -- flag )
DUP Right 0= SWAP Left 0= AND ;
Each new command is added to the tree to the left of an existing node if the name comes before in lexicographic order, and to the right if the command comes after. The commands are introduced by the word >CMD, which is used in the form
>CMD <menu_name> <word_to_execute>
The word_to_execute contains prompts and input routines to get any parameters needed from the keyboard. There is also a provision for including descriptive "help" information that will be printed if the user types HELP before typing the name on the menu.
Here is an example of how the Table command is made into a word %Table that prompts for input:
: %Table
Help:
This prints a table for the group requested
(and makes that the current group). Elements
are represented by letters A to Z and the
symbols [ ] ^ _ and `
Help;
." for " ['] Get-Grp CATCH 0=
IF CR Table THEN ;
>CMD TABLE %Table
I have written a collection of input commands. For example, Get-Grp is the command to get a group number. In all cases, the system waits for the user to type a string, which is put into the terminal input buffer (TIB) as if it had been typed at the keyboard in an interactive session. The input is then processed by Forth words that read the input stream. Also, the cursor position is saved at the start of input, and the cursor is returned to this position if there is an error in the input.
Here are other input commands that can be used for writing the prompted input sections.
2VARIABLE Save-Pos
: Get-TIB ( -- ) AT? QUERY AT
>IN @ 0 WORD
COUNT TYPE >IN ! ;
: Get-Num ( -- n ) ." Number " AT?
Save-Pos 2!
BEGIN Save-Pos 2@ AT
Get-TIB BL WORD
COUNT ?DUP 0= THROW
NUMBER? IF DROP TRUE
ELSE 2DROP BEEP FALSE
THEN
UNTIL ;
: Get-Grp ( -- n ) ." Group "
BEGIN ['] Get-Num CATCH
IF TRUE THROW
ELSE G-OK
DUP 0= IF CR 10 SPACES THEN
THEN
UNTIL ;
: Get-Set ( -- set )
." set: { " Get-TIB ." }"
0 0 WORD COUNT 2DUP UPPER 0
?DO DUP C@ ID -
DUP 0 MaxOrd 1- BETWEEN
IF ROT Member! SWAP
ELSE DROP THEN
1+
LOOP DROP ;
: Get-Ele ( -- ele ) ." element "
0 BEGIN
DROP KEY UPC ID -
DUP 0 Gord 1- BETWEEN
DUP 0= IF BEEP THEN
UNTIL ;
: Get-Ele. ( -- ele ) Get-Ele DUP .Ele ;
Here is how the interface works. The characters typed by the user are added to an incomplete command string. Each time a character is added, the tree is searched to see if the string matches the leading part of a name in the tree. If there is no match, the user is informed (by a beep), and the latest character is not accepted. If there are multiple matches, the system waits for further characters. If there is only one match, the remainder of the name is typed and the stored command is executed.
Since the user must type additional information from the keyboard, this interface has proved to be faster than one in which the user selects commands with a mouse. An additional feature of the interface is that it is very easy to add additional commands -- so the interface is extensible.
It is easy to learn to use the interface, and no programming is required. As a result, Groups32 can be easily integrated into courses in abstract algebra.
The original version of the interface used a single ordered list of commands. In later revisions I used a single binary tree. When I added permutations, I revised the code for the interface to enable using more than one tree. In Groups32 the permutation commands are in a second tree and there is a separate menu:
CREATE ELEMENTS HELP INSTALL
MAIN MENU MULTIPLY QUIT
The PERMGRPS command in the main menu switches to this package, and the command MAIN here switches back to the main system.