If a file name is given after the options, its contents will be loaded as the current script. If you don't give a file name the current script is initially empty.
Arguments following the file are permitted only when a -e option is present and in this case the file name and any arguments are placed in a list of strings called "argv".
A KRC program is called a script, which consists of a sequence of definitions each of which consists of an optional comment followed by one or more equations, one per line.
When you invoke krc, it loads a set of standard definitions called the prelude, then prints a welcome message followed by a prompt, krc>. You have now entered a KRC session. In a session you can type commands, expressions to be evaluated, and definitions to be entered in the current script. A new prompt appears as each task is completed, until you end the session.
The command to inspect a definition, say of `foo', is just the name
on a line by itself
foo
the system responds by displaying the definition associated with
`foo', which may be in the prelude or in the current script.
If the definition has more than one equation these are shown
numbered, from 1, the numbers are used when editing definitions.
You can display a section of the script, say from
the definition of `foo' to `bar' by typing
foo .. bar
The other commands all start with a / character.
Be aware that ending a session does not automatically save the current script, for that you must use /save (see below).
In the commands which follow `name' means one of the names defined in the current script;
Where it says `name(s)' you can put a name, several names separated by spaces, or a range foo..bar which refers to definitions foo through bar of the current script, or foo.. which means from the definition of foo to the end of the script.
Where it says `part(s)', this refers to equation numbers from a definition in the script, for deletion or reordering.
A part can be a single number like 1, a range like 2..4, something like 4.., which means from equation 4 to the end of the definition; part(s) means a list of these separated by spaces.
These last commands are for use in debugging the system:
For example, you could type 2+2? to obtain 4.
If the value is a data structure it is printed as you would enter it, with quote marks around strings, square brackets around lists and commas between list elements. For example (`++' joins lists together):
krc> [1..3]++["...\n"]++[2*2]?
[1,2,3,"...\n",4]
Note that with `?' control characters in a string are shown, not obeyed ("\n" means newline).
An alternative method of printing uses `!' in place of `?'.
krc> [1,2,3,"...\n",4]!
123...
4
`!' prints strings without quotes, obeying any control characters, numbers are printed in the usual way and with lists `!' scans left to right, recursively scanning any sublists encountered, printing only the atoms (numbers and strings). The effect is as if the data were squashed flat and joined up into a single string (although `!' does not actually use any additional string space).
As a general guide `?' (print values to show structure) is used when developing and testing functions and `!' (flat-print) for the final output of a program where you want to control layout. Note that `?' adds a trailing newline while `!' doesn't.
The reader may find it helpful to study the function show defined in the prelude;
Reminder: For KRC to print the value of an expression it must be followed by `?' or `!'.
A comment is the name, of a function or other data item, followed by the two
characters ":-" followed by any number of lines of text
and terminated by the first semicolon ";".
flub :- here is some text
... explaining "flub";
An equation is one line of a definition and has this form:
The optional guard is a Boolean (i.e. truth-valued) expression which determines if the equation is applicable. If the guard evaluates to "TRUE" the equation is used, otherwise it is not.
Note that equations are written one per line (no terminating semicolons needed, or allowed). Examples
We can define a function by introducing a formal parameter
Names which appear at the head of an LHS, which to this point are `radix', `girls' and `sq', are known as top-level names and have the whole script as their scope, as do the names defined in the prelude. (The scope of a name is the region of text in which it can be used with the same meaning.)
Here is a function of two parameters
More complex function definitions may require several equations, for example
Guards can also be used to do case analysis. A safer version of `fac' would be:
We have seen that a formal parameter can be a name or a literal constant. It can also be a pattern to match list structure as in this example - `rotor' carries out a simple rotation on lists of length 3.
To match lists of unknown length we use a pattern involving `:', for example the functions `hd', `tl', which return the first element of a list, and the remainder of the list without the first element, are defined
Another example is this function which copies lists of length <=2 and extracts the first 2 elements of lists with length >2.
In summary, an LHS consists of the name being defined followed by zero or more formal parameters. Each formal parameter can be
An equation with one or more patterns in its LHS applies when the actual parameters of a function invocation match the corresponding formal parameters; that is they have the same list structure and, where the pattern contains a literal, the values are equal. If there is also a guard, that must evaluate to "TRUE".
Where a definition has more than one equation they must all have the same number of formal parameters. Notwithstanding this, it is possible in KRC to define functions which take a variable number of arguments, because the right hand sides can be of varying type. (Terminology - the actual parameters of a function are also called its arguments.)
KRC supports the interactive development of scripts.
To enter definitions in the script during a session you simply type in the equations and comments at the prompt, one at a time. You can then enter expressions to test your definitions and edit them (i.e. delete, reorder etc) using the COMMANDS listed earlier and re-enter equations as needed. The line editing facilities provided by "linenoise" and/or the use of a mouse to cut and paste make this task relatively easy.
If you enter an equation with the same LHS and guard as an existing one it will replace it. Entering a comment will replace an earlier comment on the same name. To delete a comment enter an empty replacement
Another way of proceeding is to use an editor to create the script and then start a krc session with it as the file. The KRC system was designed to allow it to be used without a separate editor (back in 1980 screen editors like vi and emacs were not widely available as they are now).
The four types of value have the same "civil rights" - any value can be (i) named, (ii) included in a list, (iii) passed to a function as its argument, (iv) returned by a function as result.
There is no static type system - values of different types can be freely mixed, for example as elements of a list and a function can accept arguments of more than one type and return results of different types for different inputs. Type errors, e.g. trying to multiply two strings, are detected at run time. Languages of this kind (LISP is another example) are often called `typeless', but dynamically typed is more accurate.
A value can be tested by the four functions `number', `string', `list' and `function' and returns "TRUE" for one of these, "FALSE" for the others. There is also a function `char' which recognises strings of length 1 and a function `bool' which reconises the strings "TRUE" and "FALSE".
Numbers are integers (whole numbers, positive, negative and zero) written in the usual decimal notation, e.g. 3 -17 500
Strings are sequences of characters enclosed in double quotes, e.g.
Control characters are written using `\', e.g. "\n" is newline. The escape conventions are as in C
Note the strings "TRUE", "FALSE" are used as truthvalues, there is no separate Boolean type.
KRC has no separate type `character' distinct from `string'. A character is just a string of length 1, e.g. "a" (you cannot write this as 'a', that would not be recognised).
The prelude function `explode' converts a string into a list of characters, e.g.
KRC treats strings as atomic; they are stored uniquely in packed form. Strings can be tested for equality or order without unpacking them but to access the internal structure you must use `explode'.
There is a function `implode' which compresses a list of strings into a single string, but this is less often needed. Processing of textual data is typically done on lists of characters (or sometimes trees) and given `!' there is no need to convert the result back into a single string before printing.
Lists are written using square brackets and commas between elements, e.g. [1,2,3,"eric"]. Note the empty list, [] and singletons, e.g. [3].
An important operation on lists is `:' which prefixes an element to the front of a list. So `a:[]' is `[a]', `a:b:[]' is `[a,b]' and so on. Note also the `++' operator which appends one list to another. The elements of `x++y' are those of `x' followed by those of `y'.
As some, or all, of the elements of a list can be lists it is possible to construct multi-dimensional arrays (as lists of lists of ...) and more generally trees, of any shape. Lists can be of infinite length, for example
There is a notation `[a..b]' for a sequence of consecutive integers, e.g. `[-10..10]' is a list with 21 elements. This notation also has an infinite form, e.g. `[2..]' is a list of the integers starting at 2.
Similarly the notation `[a,b..c]' can be used for an arithmetic sequence running from a to c with step (b-a). E.g. [1,3..99] are the odd numbers from 1 to 99. Again this has an infinite form, e.g. [0,-5..]
A list can be applied to a non-negative number, n say, to extract its n'th element (counting from 0). So given
Functions: a function calculates an output value from given input value(s). The rules of calculation are given by its defining equations (except for a few built-in functions defined in machine code).
Applying a function to its input values (or arguments) is done by juxtaposition, e.g.
A prefix or infix operator in single quotes denotes the corresponding one- or two-argument function, e.g.
Continued application: a function application can return a function, e.g. (ops n) is a function, which one depends on `n'. We can immediately apply this to its arguments, thus
Partial application: a function of two or more arguments can be applied to a smaller number of arguments and the result is a function that is waiting for the remaining arguments. For example
Partial application works because KRC uses a model of functions derived from combinatory logic. In this model, all functions actually take a single argument. An n-ary function, for n>1, is a function that, when applied to its argument, returns an (n-1)ary function that is waiting for the next argument. So taking the case n=3 as an example
The second column gives associativity:- a left associative operator, e.g. `-' has
The third column gives a brief statement of meaning. Where needed the notes below add further detail.
operator | associativity | meaning |
: ++ -- | right | list prefix, append, listdiff |
| | right | logical or |
& | right | logical and |
\prefix | logical not | |
> >= \= == <= < | see below | comparisons |
+ - | left | add, subtract |
+ - | prefix | plus, minus |
* / % | left | multiply, integer divide, remainder |
** . | right | exponent, function-compose |
# | prefix | length of list |
The application of a function to its arguments binds more tightly
than any operator. Parentheses (...) can be inserted freely
in expressions to enforce the intended parse or to make it clearer to the reader
- redundant parentheses do not change the meaning (this is true both in expressions
and in formal parameters).
The operators : (prefix) and ++ (append) have been discussed earlier, in the section on DATA TYPES. The expression x -- y returns a list of the elements of x without those that appear in y, the exact definition is given by the prelude function listdiff.
The logical operators |, & do not evaluate their second operand if this is not needed.
The relational operators >, >=, ==, <=, < have a special syntax which allows continued relations, as commonly used in mathematics books. For example
The operators == and \= can be used to test for equality or inequality on any pair of values, returning "TRUE" or "FALSE". Values of different types are always unequal. Two lists count as equal if and only if they are of the same length and (recursively for sublists) corresponding elements are equal.
Equality tests between functions give unpredictable results and should not be used. (Example: `map == map' has value "TRUE" but `map abs == map abs' is "FALSE".)
The order testing operators > >= <= < work on numbers in the usual way and on strings compare according to the C function strcmp(). For words all in upper case, or all in lower case, this amounts to dictionary order, but be aware that upper case letters precede lower case letters, so "ZEBRA" < "ant". It is an error to test lists or functions for order, or two values of different type.
+ - * / are the usual arithmetic operations, with % for remainder. KRC arithmetic deals only with integers thus `/' discards the fractional part, rounding towards 0, while a % b takes the remainder on dividing `a' by `b', the sign of the result being that of `a' (these rules for integer division and remainder are the same as C).
Prefix `-' reverses the sign of its integer operand (leaving 0 unchanged). A negative constant like `-1' is, syntactically, an operator expression and must be parenthesised when passed to a function, thus `f(-1)' whereas `f -1' would attempt to subtract 1 from f. Prefix `+' does nothing and is discarded.
a ** b raises `a' to the power of `b' which must be non-negative.
The composition of two functions `f . g' is defined as follows
The operator # gives the length of a list, for example `#[1,2,3]' is 3. To find the length of a string use the prelude function printwidth.
A prefix or infix operator in single quotes denotes the corresponding one- or two-argument function. For example ´+´ is the addition function and ´#´ and ´\´ are functions which take the length of a list and the negation of a truthvalue. Note that ´-´ is subtraction, for unary minus you can use the prelude function neg.
We start with some simple examples
The next example is a function for finding the factors of a number
A ZF expression can have two or more generators, so
Our last example finds all positions on a chess board which are a knight's move from [x,y]
The general form of a ZF expression is
If the first qualifier is a generator, which is usually the case, the initial `;' can be written `|', which aids readability.
For examples of programming with ZF expressions see David Turner's papers "The Semantic Elegance of Applicative Languages'' (1981) and "Recursion Equations as a Programming Language" (1982).
(Historical note: The semantics of ZF expressions in KRC differ from those of modern list comprehensions in interleaving outputs of multiple generators to ensure that all combinations are eventually reached, even with two or more infinite generators. The motivation was to make them behave more like set comprehensions, whence the use of {}. List comprehensions with square brackets and the now familiar "nested loop" semantics first appeared in Miranda, in 1984.)
To list the names defined in the currently loaded prelude during a KRC session, type
The standard prelude is usually at /usr/lib/krc/prelude but may be placed elsewhere by the installer. To view the standard prelude in a KRC session, say "/help prelude".
Another library in place of the standard prelude can be specified on the command line when KRC is invoked by the option -l lib. If you invoke KRC with option -n, no prelude is loaded.
If KRC is invoked with option -L, a legacy prelude is used in place of the standard one. To view this in a KRC session, say "/help lib1981".
Note that without a prelude you cannot use ZF expressions, whose implementation requires interleave nor can you use the `--' operator, which requires the function listdiff.
Escape to Unix shell: type Ctrl-Z to suspend KRC and return to Unix command line, say fg to resume the KRC session.
Other flags such as "-l lib" for an alternative prelude, "-h size" for a larger heap, can precede "-e".
The name by which the script is called, followed by the command-line arguments that the user supplies when it is run, are placed in a list of strings called "argv".
Example: A simple command to display the contents of files. Put the following 2 lines in a file called "list".
Any KRC script can be made executable by placing a "magic string" at the start. When used as the script in an interactive KRC session an initial line in `#!' is treated as a comment and ignored; it has effect only if the file is invoked as a command on the Unix command line.
The base for indexing lists has been changed from 1 to 0. The option -z reverts to lists being indexed from 1 (this may be needed for legacy KRC scripts dating from the 1980's).
A revised prelude has been provided, with some more efficient definitions (e.g. reverse, sort) and a more modern collection of functions. A legacy prelude from 1981 is also available (option -L).
Escape characters in strings, "\n" etc., as in C, have been added. KRC as originally designed used instead names for special characters: nl np quote tab vt, these remain in the prelude. Example: instead of "123\tgo\n" you can say ["123",tab,"go",nl] to get the same effect with ``!''.
A distinction has been introduced between `=', definitional equals and `==' the equality test (KRC originally used `=' for both).
In-line comments, from "||" to end of line, have been added, thus
The length of a string limited to 255 characters. The space used by strings created during a session is never freed, mitigated only by the fact that multiple copies of the same string are shared. This means that programs which create a lot of temporary strings as part of their operation will soon run out of the space in which strings, identifiers, file names and comments are stored. Note, however, that KRC's ``!'' output mode removes much of the need to create temporary strings.
Numbers are limited in range to that of the underlying processor's machine word, i.e. they are signed 32-bit or 64-bit integers. Calculations which exceed this range cause a run-time error.
If linenoise is enabled, multiline comments cannot be entered interactively in a KRC session.
KRC looks for the prelude first in ./krclib if present, then in /usr/lib/krc (this may be changed by the installer).
This implementation was created by translating the original BCPL sources into C for the Unix family of operating systems.
KRC is Copyright (c) D. A. Turner 1981 and is released under an open source license, for terms see the file "COPYING" included in the distribution.