Skip to content

12. Working with hql

The language is half of what you use; the other half is the command and what it says back. This chapter is about the tools: the commands, the reports, and the messages hql writes when a program is wrong.

The commands

Command What it does
hql eval <program> check and evaluate a program given as an argument
hql run <file> check and evaluate a program in a file; - reads standard input
hql check <file> write the program's type, and the signature of every alias, without evaluating
hql repl read, evaluate and print, keeping bindings between lines
hql render <file> build a document from its cells (chapter 11)
hql builtins list every step, by the provider that implements it, with its signature
hql config the settings in force, and where each came from
hql doctor check the semantic-search chain and name the first missing part

--vault <dir> names the vault, --to <format> the output format, and --envelope json wraps the answer for another program.

The REPL

hql repl keeps its bindings from one input to the next. The arrow keys edit a line and recall earlier inputs, from a history kept between sessions. An input goes on over several lines while a bracket is open, or while the next line opens with |, so every program in this book can be pasted in as it is written. :type asks for a type, and :quit leaves, as do quit, exit and Ctrl-D:

$ hql repl
hql 0.5.0. `:help` for commands, `:quit` to leave.
hql> shelf = [412, 280]
()
hql> shelf | sum
692
hql> :type shelf
List<Int>
hql> :quit

What a step takes

hql builtins lists every step with its signature, one line per form:

$ hql builtins
core 0.5.0 (always available)
  size
    Collection<T> | size<T>() -> Int
    Count all element occurrences.
  contains
    Collection<T> | contains<T>(value: T (positional)) -> Bool
    Whether a value occurs in the collection.
  …

A function of a module that the program has not imported is listed too, so the import it needs can be looked up. import lexical makes a module visible; lexical.lexical(…) names a function with its module, when two visible modules declare one name and the input does not tell them apart. The modules of lib/std/prelude.hql, string, seq, math, option, result, graph, format and io among them, are visible in every program unless the vault's hql.toml says prelude = false.

Reports

A run produces a value and a queue of reports: warnings that change nothing, errors that make a result wrong, failures that make one impossible. Every report names where it points, by line and column.

By default hql stops at the first error. --report collect reports every error it can find:

$ hql --report collect eval 'a = nosuchthing
b = alsomissing'
name error: `nosuchthing` is not bound
 --> <expression>:1:5
  |
1 | a = nosuchthing
  |     ^^^^^^^^^^^

name error: `alsomissing` is not bound
 --> <expression>:2:5
  |
2 | b = alsomissing
  |     ^^^^^^^^^^^

2 reports: 0 failure, 2 error, 0 warning

A misspelled step suggests the nearest one, and a retired name says what replaced it:

$ hql eval '[1, 2] | mapp(n => n)'
name error: `mapp` is not a pipeline step; did you mean `map`?

A warning never changes the exit status. Names have one casing per kind — snake_case for bindings, functions and fields, PascalCase for types — and a name off its kind's convention is a warning where it is written:

$ hql eval 'bookCount = 7
bookCount'
7
type warning: `bookCount` is a binding, written in snake_case
 --> <expression>:1:1
  |
1 | bookCount = 7
  | ^^^^^^^^^

Logging from a program

A program reports on itself with a logger. import logging provides one; it writes structured events to an endpoint of its choosing, apart from the result:

$ hql --vault examples/tutorial 'import logging
log = Logger(stderr, Text, name = "books")
books = cards | filter(c => c.metadata.category == "book")
log | info("selected", {category: "book"})
books | size'
INFO books selected {category: "book"}
7

--log-level debug lowers every logger's threshold, and --log-level warn raises it, without changing the program.

--envelope json carries every report, whatever the level, as data.

Settings

The report mode and level come from the command line, then the vault's hql.toml, then the environment ($HQL_REPORT, $HQL_REPORT_LEVEL), then the defaults. hql config says which applies, and why:

$ hql --vault examples/tutorial config
report mode: strict (from the default)
report level: warning (from the default)
vault: examples/tutorial (14 cards)

What is next

So far every program read a vault or its own values. Chapter 13 reads files and standard input, and writes files and standard output.