Hilde lernen
Diese Tour zeigt vollständige Programme aus dem Verzeichnis examples/ des Hilde-Repositorys. Zu jedem steht die Ausgabe, die es beim Bauen dieser Seite tatsächlich erzeugt hat. Die Regeln dahinter erklären die Grundlagen, jeden Fehlercode die Seite Fehlercodes.
Hallo, Welt
Datei: HelloWorld.hih
module Example.HelloWorld is
"""
No contract: the exit code of the programme, the result of what it did.
"""
function main(): ExitCode;
end module.
Datei: HelloWorld.hiq
module body Example.HelloWorld is
function main(): ExitCode is
printLn("Hello, world!");
return ExitSuccess();
end;
end module body.
Ausgabe von ./main (Exit-Status 0):
Hello, world!
examples/hello-world im Hilde-Repository, hilde 1.0.0Records mit Invariante
Interval ist ein Record mit einer Invariante. Sie wird jedes Mal geprüft, wenn ein Wert sein Modul verlässt. makeInterval liefert einen Option-Wert: Ein Intervall, dessen unteres Ende über dem oberen liegt, wird mit None abgelehnt, statt das Programm abstürzen zu lassen.
Datei: Interval.hih
"""
A closed interval of whole numbers whose low end is never above its high
end. The type is opaque, so only this module builds and changes one, and
its invariant is checked whenever a value leaves the module.
"""
module Example.Interval is
"""
An interval from low to high, both included.
"""
type Interval: Linear;
"""
The interval from low to high, or None when low is above high.
No contract: an Option result, which an ensures cannot look into.
"""
function makeInterval(low: Nat32, high: Nat32): Option[Interval];
"""
How many numbers the interval holds: high minus low plus one.
No contract: a number read from its argument; its type gives its range, and nothing cheaper holds.
"""
generic [R: Region]
function width(interval: &[Interval, R]): Nat32;
"""
Moves the high end up by amount. Returns false and leaves the interval
as it was when the high end would pass the largest Nat32.
No contract: the answer is a Bool, nothing cheaper holds.
"""
generic [R: Region]
function stretch(interval: &![Interval, R], amount: Nat32): Bool;
"""
The high end of the interval.
No contract: a number read from its argument; its type gives its range, and nothing cheaper holds.
"""
generic [R: Region]
function highEnd(interval: &[Interval, R]): Nat32;
"""
Ends the interval.
No contract: it only frees or closes what it is given.
"""
function destroyInterval(interval: Interval): Unit;
end module.
Datei: LearnRecords.hiq
import Example.Interval (
Interval,
makeInterval,
width,
stretch,
highEnd,
destroyInterval
);
module body Example.LearnRecords is
record Day: Linear is
morning: Interval;
evening: Interval;
end;
-- A write reference to the evening alone, from a write reference to
-- the whole day. It uses up the reference to the day.
generic [R: Region]
function stretchEvening(day: &![Day, R], amount: Nat32): Bool is
return stretch(&!(day->evening), amount);
end;
generic [R: Region]
function hours(day: &[Day, R]): Nat32 is
return width(&(day->morning)) + width(&(day->evening));
end;
function makeDay(morning: Interval, evening: Interval): Day is
return Day(morning => morning, evening => evening);
end;
function main(): ExitCode is
case makeInterval(9, 5) of
when Some(value as wrong: Interval) do
printLn("an interval from 9 to 5, which must not be");
destroyInterval(wrong);
when None do
printLn("an interval from 9 to 5: refused, the low end is above the high end");
end case;
case makeInterval(8, 11) of
when Some(value as morning: Interval) do
case makeInterval(17, 19) of
when Some(value as evening: Interval) do
var day: Day := makeDay(morning, evening);
print("hours in the day: ");
printLn(hours(&day));
print("the evening stretched by two: ");
printLn(stretchEvening(&!day, 2));
print("stretched past the largest number: ");
printLn(stretchEvening(&!day, maximum_nat32));
borrow view: &[Day, V] := &day do
print("the evening ends at: ");
printLn(highEnd(&(view->evening)));
print("hours now: ");
printLn(hours(view));
end borrow;
let { morning as m: Interval, evening as e: Interval } := day;
destroyInterval(m);
destroyInterval(e);
when None do
printLn("no evening");
destroyInterval(morning);
end case;
when None do
printLn("no morning");
end case;
return ExitSuccess();
end;
end module body.
Ausgabe von ./main (Exit-Status 0):
an interval from 9 to 5: refused, the low end is above the high end hours in the day: 7 the evening stretched by two: true stretched past the largest number: false the evening ends at: 21 hours now: 9
examples/learn-records im Hilde-Repository, hilde 1.0.0Vorlagen
Neben dem Modul liegt eine Vorlage in Jinja2-Syntax. Der Compiler prüft sie gegen den Record, den sie bekommt, und übersetzt sie in Hilde-Code. Zur Laufzeit wird nichts mehr geparst.
Datei: order.jinja
Order for {{ customer|upper }}
{%- for line in lines %}
{{ loop.index }}. {{ line.name }}, {{ line.count }} of them{% if loop.last %} (the last line){% endif %}
{%- endfor %}
{% if rush %}Ship today.{% else %}Ship this week.{% endif %}
Datei: LearnTemplate.hiq
import Standard.Buffer (
Buffer,
allocateEmpty,
insertBack,
removeLast,
destroyEmpty,
length
);
import Standard.String (
String,
fromLiteral,
destroyString,
length as textLength,
getSpan
);
import Standard.StringBuilder (
StringBuilder,
makeStringBuilder,
finalize
);
import Standard.Template (
Render
);
module body Example.LearnTemplate is
record Line: Linear is
name: String;
count: Int32;
end;
record Order: Linear is
customer: String;
lines: Buffer[Line];
rush: Bool;
end;
-- The template order.jinja, in the syntax of Jinja2, is read by the
-- compiler and turned into code here: a name in the template that the
-- record does not have, or a filter that does not exist, is a compile
-- error, not a surprise at run time.
generic [R: Region]
function render(order: &[Order, R]): String is
var out: StringBuilder := makeStringBuilder();
@template("order.jinja", order, out);
return finalize(out);
end;
function destroyLines(lines: Buffer[Line]): Unit is
var rest: Buffer[Line] := lines;
while length(&rest) > 0 do
let line: Line := removeLast(&!rest);
let { name: String, count: Int32 } := line;
destroyString(name);
end while;
destroyEmpty(rest);
return nil;
end;
function main(): ExitCode is
var lines: Buffer[Line] := allocateEmpty();
insertBack(&!lines, Line(name => fromLiteral("apples"), count => 6));
insertBack(&!lines, Line(name => fromLiteral("pears"), count => 2));
insertBack(&!lines, Line(name => fromLiteral("plums"), count => 12));
let order: Order := Order(
customer => fromLiteral("Ann"),
lines => lines,
rush => true
);
let text: String := render(&order);
printLn(getSpan(&text, 0, textLength(&text) - 1));
destroyString(text);
let { customer: String, lines as rest: Buffer[Line], rush: Bool } := order;
destroyString(customer);
destroyLines(rest);
return ExitSuccess();
end;
end module body.
Ausgabe von ./main (Exit-Status 0):
Order for ANN 1. apples, 6 of them 2. pears, 2 of them 3. plums, 12 of them (the last line) Ship today.
examples/learn-template im Hilde-Repository, hilde 1.0.0Ein Graph
Standard.Graph ist ein gerichteter Graph mit Werten an Knoten und Kanten. Das Beispiel sucht in einer kleinen Karte den Weg mit den wenigsten Straßen und den mit den wenigsten Kilometern. Den Quelltext finden Sie unter examples/learn-graph.
Ausgabe von ./main (Exit-Status 0):
fewest roads: Aachen Cologne Frankfurt fewest kilometres: Aachen Bonn Frankfurt, 265 km
examples/learn-graph im Hilde-Repository, hilde 1.0.0Tasks
Vier Tasks laufen in einem gemeinsamen Scope, ein fünfter hat seine eigene Arena. Die Ausgabe ist bei jedem Lauf dieselbe. Den Quelltext finden Sie unter examples/learn-tasks.
Ausgabe von ./main (Exit-Status 0):
5239625 36552125 99114625 192927125 333833500 338350
examples/learn-tasks im Hilde-Repository, hilde 1.0.0Weitere Beispiele
Das Repository enthält sechzig Beispielverzeichnisse. Die Verzeichnisse learn-* zeigen jeweils eine Eigenschaft oder ein Modul, etwa reguläre Ausdrücke, die Sandbox, SQLite und SQLCipher, Passwörter, Sitzungen, einen FastCGI-Server, Dateien, Zeit und Archive. In jedem liegt eine README.md, die erklärt, wie man das Beispiel baut und was herauskommt. Die Anleitung Hilde lernen beginnt beim ersten Programm, und die Seite Fallstricke zeigt typische Fehler beim Schreiben von Hilde mit falschem und richtigem Code.
Playground
Geplant ist ein Playground im Browser auf Grundlage des WebAssembly-Ziels von Hilde. Ein Modul für wasm32-wasi wird mit zig cc gebaut, und das Repository enthält je ein Beispiel für den Browser und für die Kommandozeile (examples/wasm-browser und examples/wasm-cli). Auf dieser Website gibt es noch keinen Playground. Die Website kommt ohne JavaScript aus.