What are commands?#
A command is a way of describing our program’s behaviour. There are other things that affect how a program works, but commands are the primary one. Crochet’s commands are a bit similar to “functions”, “procedures”, “routines”, and “methods” in other programming languages, but they have a few unique things about them.
For example, consider the following command declarations:
command true and true = true;
command boolean and boolean = false;
This piece of code defines two commands, but both of them have the same
name: _ and _
. The underscores in the name indicate where arguments
to this command would go. In the definition, these underscores indicate
the places where the requirements for executing the command go.
So, for the first command, we can execute it whenever both of the arguments
are an instance of the type true
. For the second one, we can execute
the command whenever both of the arguments are an instance of boolean
.
Remember that types in Crochet create an hierarchy, so the boolean hierarchy
looks like this:
+ any
|
`--+ boolean
|
|--o true
`--o false
At the root of this hierarchy we have the type any
. Then we have boolean
descending from it. And both true
and false
descending from boolean
.
When we use a command, Crochet will pick the one whose requirements are most
closely matched to the arguments.
For example, let’s say we have the following use of a command:
true and true
Crochet will find all of the commands that have been declared with the name
_ and _
and then pick one to execute. First, we need to match all
requirements. In this case both commands we’ve declared fulfill all of
the requirements: the value true
is both an instance of the type true
,
and transitively, an instance of the type boolean
(and any
!).
Then, since we have more than one candidate, Crochet needs to somehow
disambiguate this. And the way it does so is by picking the closest matching
one. That is, if we have to walk up the hierarchy up to any
, the closest
matching is the one we have to take the least amount of steps. Here, the
command true and true
requires no steps on both sides, whereas the command
boolean and boolean
requires one step on each side. Thus, Crochet picks
true and true
, yielding the result true
.
On the other hand, if we had the expression true and false
, or
false and true
. Or even false and false
, the requirements for the
true and true
command wouldn’t be matched, and we’d end up executing
the boolean and boolean
command, yielding the result false
.
So, to answer the opening question: a Crochet command is like a function, it has a name and we can execute that function to do something. But multiple commands can share the same name, and when we execute one, Crochet will pick up the closest one that matches all requirements. Some languages call this a Multi-method.
Commands are global#
In Crochet, commands are always global. This might come as a surprise since
almost everything else in Crochet is qualified by the package they’re in.
So if you define a type like player
, what you’re really defining is
the type some-package/player
. But this is not the case with commands.
If you define a command _ and _
, its name will always be just _ and _
,
regardless of which package it’s defined in.
Signatures#
Because commands can have the same name, Crochet needs a different way to refer to specific commands. To do this it has a concept called a Signature. A Signature combines the name of a command with the requirements to execute the command.
Signatures seem simple at the surface, but they’re actually a fairly complex topic, so they’re covered in depth in their own section: Signatures and their uses.
Behaviours#
So, if a command describes a “program’s behaviour”, how exactly does it do that? Well, if the left side of the command declaration is its signature, then the right side is its behaviour. Here we use expressions to describe what the program does if the command is executed.
The distinction between “expression” and “signatures” isn’t always very
obvious. A signature may only contain types, and expressions may only
contain values. But because these are two different concepts, they may
(and in a lot of cases do!) look pretty much the same. true and true
can either be a signature (concerning the type true
), or an
expression (concerning the value true
).
Since the topic is vast, we cover expressions in their own chapter.