Concept guide
How Vision thinks
Vision programs are made from described things and verbs. A small marker shows where that work reaches beyond the program.
Start with the things in the problem
A kind describes a thing by naming the facts it holds. The example below has a note with a title and a body. Later, the construction block builds one note and fills those two fields.
This keeps related facts together. Code can pass the note around as one value instead of carrying its title and body as separate values that happen to belong to each other.
Give the work a verb
Verbs name what the program can do. render takes a note and answers with text. It only reads its input and builds a new value, so its declaration and its calls need no world-touch marker.
A verb can call another verb. In the example, save calls the calm render verb before it writes anything. The names keep the intent visible: render the note, encode the result, then save it.
Calm work stays unmarked
Local arithmetic, comparisons, and value construction stay inside the program. They need no >>. Parentheses make the order of mixed arithmetic explicit here; the whole calculation remains calm.
to begin:
the width is 40
the depth is 3
the tiles is (the width times the depth) plus 2
say "we need {the tiles} tiles"to begin:
the width is 40
the depth is 3
the tiles is (the width times the depth) plus 2
say "we need {the tiles} tiles"Mark the boundary with >>
>> means that a line touches the world outside the program. The marker appears on the file write, on the call to the effectful save verb, and on each verb declaration whose body reaches that boundary.
The compiler checks both directions. Leave >> off an effectful line and the program is rejected. Put it on a calm verb and the program is rejected too. Calls carry the rule with them, so a verb that reaches the world through another verb must also say so.
>> to begin:
the note is "a line written down"
the data is the note encoded as bytes
>> write the data to the file at "note.txt"
| unwritable: say "could not write the note" and stop>> to begin:
the note is "a line written down"
the data is the note encoded as bytes
>> write the data to the file at "note.txt"
| unwritable: say "could not write the note" and stopPut the pieces together
kind note:
title: text
body: text
to render(note: note), returns text:
answer "{note.title}: {note.body}"
>> to save(note: note, path: text):
the rendered is render(note)
the data is the rendered encoded as bytes
>> write the data to the file at path
| unwritable: say "the note could not be saved" and stop
>> to begin:
the field note is a note:
title is "Field notes"
body is "Mark the line that reaches outside."
say render(field note)
>> save(field note, "field-note.txt")kind note:
title: text
body: text
to render(note: note), returns text:
answer "{note.title}: {note.body}"
>> to save(note: note, path: text):
the rendered is render(note)
the data is the rendered encoded as bytes
>> write the data to the file at path
| unwritable: say "the note could not be saved" and stop
>> to begin:
the field note is a note:
title is "Field notes"
body is "Mark the line that reaches outside."
say render(field note)
>> save(field note, "field-note.txt")say is the deliberate small exception. Direct console output stays unmarked. If the value on that line reads the clock or environment, that world touch still needs >>. File access, networking, clocks, randomness, and environment reads all use the visible boundary.
Try the boundary
Change the title or body and run the program again. Then remove the marker from the call to save in begin and compile once more. The compiler rejects the call because its effect is no longer visible. Restore the marker, and the program is honest again.
Next, read a larger Vision program and see how these same pieces fit together across more than one verb.