Clue (oklopol)
- You may be looking for the other language named Clue (by Keymaker).
Clue is a programming language created by User:oklopol based on the example-driven programming paradigm. Programs define functions using 'clues' that either list the possible building block functions that a function can be made from, or provide example input-output pairs for the function in question. These clues are compiled into a function.
Syntax
A Clue program is a set of function clues. Each clue is compiled to a function based on the examples and the usable function given. Functions are created from zero or more example commands, and exactly one bag command. For example, if clue function
is the clue function being clued, a bag command is of the form
clue function ~ helper 1; helper 2; ...; helper n
where helpers can be names that refer to helper functions or clue objects (defined later). The above code says that the code for clue function
contains only the helpers listed above.
As you can see, identifiers can include spaces. Another thing to note: in Clue, :
and ..
are equivalent, and more generally, the only thing that matters in a string of .
and :
is the total number of dots.
Example functions come in two forms: base examples and recursion examples. The general form of a base example is
clue function ~ {. inputs 1 -> output 1 . inputs 2 -> output 2 ... . inputs n -> output n }
The general form of a recursion example is
clue function ~ {:. inputs 1 -> output 1 : subinputs 1.1 -> suboutput 1.1 ... : subinputs 1.k -> suboutput 1.k ... :. inputs n -> output n : subinputs n.1 -> suboutput n.1 ... : subinputs n.k -> suboutput n.k }
All inputs in example commands are a whitespace separated list of clue objects. Within one example, all these lists should be of the same length (the length being the arity of the function being defined).
There are two types of objects in clue, lists and integers. List elements are written between []-brackets and whitespace separated. Numbers are written in the obvious way.
Some of the more precise details of the syntax are unknown.
:::
starts a comment; the rest of the line is simply ignored.
Semantics
Each function clue is compiled into a function. The function will only use the various combinations of the helper functions and helper objects listed in the bag of that function clue. All clue functions have a single branching function (made out of the contents of the bag) whose return value, when given the input, determines what function of its input the clue function computes.
Branching
Each example command is a separate logical branch of the function, that is, when a function is executed, a branching function is applied to the inputs, and the result determines the branch taken. Each example command corresponds to a single branch of the function.
Each example command that is associated with the function has its own code for computing the output from the inputs, and one input value of the branching function is associated with each of those branches. There can be one default branch without such a value, and this branch is taken by default, if the branching function gives a value not associated with any branch. The branching function is composed of the functions of the function bag, and the compiler generates it so that it must 1) return the same value for all the example inputs within each example command, except for at most one branch. 2) return different values for inputs of different example branches. It is not specified which such function the compiler infers.
Base example branches
Base examples are compiled into base functions, composed of the contents of the bag, such that for any input given in the example command, the corresponding output is returned. Recursion of any kind is not allowed — the dependencies of functions on each other must form a tree. (Recursive examples add self-loops in this tree, but mutual recursion is not possible at all.) Which such function the example is compiled into is again not specified.
If the function that corresponds to the base branch is called, and this branch is taken, the base function the example was compiled into is called with the arguments of the original function call as the arguments, and the result of the function call is the result of the base function associated with this branch.
If multiple examples are given in a single example command, the same code should work for all examples.
Recursive example branches
A recursive example
:. inputs -> output : subinputs 1 -> suboutput 1 ... : subinputs k -> suboutput k
is, similarly to the base example case, compiled into a function that is called if this branch is taken, with the arguments of the original function call. Now, code for turning inputs into outputs is not inferred. Instead, code is inferred for turning inputs into subinputs 1, then inputs and suboutput 1 into subinputs 2, then inputs, suboutput 1 and suboutput 2 into subinputs 3, and so on. Finally, from all the outputs and inputs, output is constructed.
When called, the function the command is compiled to will compute the subinputs as explained before, call itself recursively on the subinputs, and then use inputs and suboutputs to construct the final output. The resulting function might not actually turn "inputs" into "outputs", although it's good programming practise to only write functions with this property (and quite a challenge to write meaningful ones without it).
Again, multiple examples can be given in the same command, and the same code should work for the exact same computations. Once again, as long as the compiled code has the properties explained, and is built from the contents of the bag, it isn't specified what it is.
Running the program
A Clue program cannot actually be executed from within source code, but most Clue compilers allow testing of the compiled functions with user given input.
Examples
External resources
A reference implementation for Clue 1.0 is available at vjn.fi (dead link), but that language is considered highly obsolete, and nobody should use it. As for a Clue 1.25 implementation, perhaps the kind folk in #esoteric might know.