Your first session: install, the REPL, and the types
Amber is one folder. There is no installer, nothing is copied anywhere, and deleting the folder uninstalls it completely.
Getting a prompt
git clone https://github.com/BonucciAndrea/amber
cd amber
./a # builds if needed, then drops you at the REPL./a rebuilds whenever the sources are newer than the binary, so after a git pull the first run is a build. For the fastest build on your own machine:
AMBER_NATIVE=1 ./a # -march=nativeLine editing is built in: history, Ctrl-A/E, Ctrl-W/U/K, reverse search, multi-line continuation. Wrapping Amber in rlwrap fights the built-in editor and gives you a worse terminal rather than a better one.
The REPL is the documentation
Before anything else, learn these four. They will answer more questions than this website will:
| command | what it gives you |
|---|---|
\ | the help menu, every topic on one screen |
\h | the one-screen cheat-sheet of every verb |
\v · \f | variables and functions currently defined |
\\ | exit |
Typing \ on its own prints the menu; each topic is one keystroke from there.
Atoms and vectors
An atom is a single value. A vector is many of one type. They are different things, and the type tag tells you which:
@ 1 / `i -- integer atom (lower case = atom)
@ 1 2 3 / `I -- integer vector (upper case = vector)
@ 1.5 / `f -- float atom
@ 1.5 2.5 / `F -- float vector
@ "a" / `c -- char atom
@ "abc" / `C -- char vector, i.e. a string
@ `sym / `s -- symbol atom (interned, compares by id)
@ `a`b`c / `S -- symbol vector
@ (1;`a;"b") / `A -- generic list: mixed typesA symbol is interned once and afterwards compared as a 4-byte id, never character by character. Every column of instrument names in a tick table should be `S, never `C. This is the difference between a group-by that takes 34 ms and one that takes 587.
Nulls, infinities and the empty vector
0N / integer null
0n / float null (NaN)
0w -0w / positive and negative infinity
^ 1 0N 3 / 0 1 0 -- ^ tests for null
0N ^ 1 0N 3 / 1 0N 3 -- x^y fills nulls in y with x... careful:
0 ^ 1 0N 3 / 1 0 3 -- fill the nulls with 0
!0 / an empty integer vector
0#` / an empty symbol vector -- 0# takes nothingFloat nulls (0n) propagate silently through arithmetic, which is usually what you want in a time series and occasionally a trap. Int nulls stay null too, as q's do (since 2.9.0): 0N+1 is 0N. The q-named sum, avg, min and max skip nulls the way q does, though (since 2.4). ^x is how you check.
Assignment and functions
a: 42 / local assignment
a:: 42 / global assignment (from inside a function)
f: {x + y} / a lambda; x, y, z are the implicit arguments
f[1; 2] / 3 -- bracket call, semicolon separated
g: {[price;size] price * size} / or name them explicitly
g[10.5; 100] / 1050.0As in q, a named function of two arguments can sit between them: sz wavg px is wavg[sz;px], and your own work the same way (g:{[a;b] a*b}; 3 g 4). A lambda written in place doesn't: {x+y}[3;4], not 3 {x+y} 4.