-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: Document the basics of controllers.
Fixes #82.
- Loading branch information
1 parent
e7e6c20
commit 961c650
Showing
2 changed files
with
65 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
=========== | ||
Controllers | ||
=========== | ||
|
||
Sometimes, when designing an API, we want to be able to customize Monte's | ||
behavior while retaining the general Monte idioms for values and layouts. | ||
Controller syntax lets us change behavior of code blocks in a safe and | ||
coherent fashion. | ||
|
||
How to Implement a Controller | ||
============================= | ||
|
||
Controller Expansion | ||
-------------------- | ||
|
||
Suppose that we have a standard if-expression:: | ||
|
||
if (cond()) { | ||
advance() | ||
} else { | ||
fallback() | ||
} | ||
|
||
Now, suppose that we wished to customize this. We could define a controller | ||
named ``ifController``, and then call it with very similar syntax:: | ||
|
||
ifController (cond()) do { | ||
advance() | ||
} else { | ||
fallback() | ||
} | ||
|
||
This expands roughly to the following:: | ||
|
||
(ifController :DeepFrozen).control("do", 1, 0, fn { | ||
[[cond()], fn { advance() }] | ||
}).control("else", 0, 0, fn { | ||
[[], fn { fallback() }] | ||
}).controlRun() | ||
|
||
We see that controllers must be ``DeepFrozen``, and that each code block, which | ||
we'll call a "lambda-block", corresponds to a ``.control/4`` call, with a | ||
``.controlRun()`` to indicate the end of blocks. | ||
|
||
Control with Lambda-Blocks | ||
-------------------------- | ||
|
||
The power of controllers is locked within the lambda-blocks. Each block is a | ||
function which returns an ``[args, lambda]`` pair. The controller can choose | ||
how many times it wants to call the block, and similarly, the block can return | ||
new arguments every time it is called. Indeed, note above that ``cond()`` is | ||
called every time its containing lambda-block is called. | ||
|
||
What are the other arguments to ``.control(verb :Str, argCount :Int, paramCount | ||
:Int, block)``? The control verb is the bare word preceding each block. The | ||
argument count specifies how many arguments will be returned by the block. | ||
Where are the parameters? | ||
|
||
Let us imagine another hypothetical controller:: | ||
|
||
m (action) do x { f(x) } | ||
|
||
In this situation, ``x`` is the one and only parameter, and so the controller | ||
receives a parameter count of ``1``. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -64,6 +64,7 @@ Language Reference | |
miranda | ||
iteration | ||
custom-guards | ||
controllers | ||
slots | ||
auditors | ||
semantics | ||
|