Arturo is a very simple language. Even without any prior experience, I estimate it would take you roughly half an hour before you are comfortable enough to write your first program.
Here, you'll find everything you may need to know about the language (and perhaps a bit more). In a single page.
- Introduction
- The basics
- Important concepts
- Syntactic sugar
- Conclusion
Arturo's syntax is probably as easy as it could get. Basically, you could say: there is no syntax.
Let's try to resume some key points of Arturo's no-syntax:
- Code is just a list of words, labels, symbols, values and attributes (you'll learn what all this is about very soon!)
- Code can be grouped into blocks (that is: a list of words, labels, symbols, and values within square brackets:
[ ... ] - A block has no meaning until it is given one, or interpreted within some specific context, that is:
[ lorem ipsum ]is perfectly valid Arturo code, until you try to "run" it - where the interpreter will complain that it has no idea whatloremandipsumis. Pretty much like if I tell you a word in Swahili - you'll most likely need a dictionary to figure out what it might mean. - There are no reserved "keywords". Every word can be re-defined.
- You can format your code any way you want: no semicolons to add, no obligatory newlines, no commas, no parentheses, no Python-style indentation rules
- Every function expects a pre-determined number of arguments. Initially, we check during evaluation, and during runtime, we "consume" values until we reach the number of arguments required.
As you can see, there is not much to learn from scratch here:
Once you learn what the language building blocks are & a few details about precedence and evaluation, then only with the Library Reference at hand (the built-in functions that are already there for you, available to use), you're pretty much ready to write any program. ;-)
So, let's get to the gist of the matter!
Words in Arturo are pretty much like words in English: a series of characters separated by spaces or some symbol. E.g.: this is a series of words (in this case, this, is, a, series, of, words are all - well... - words.
💡 In Arturo, a word can be start with any letter or underscore followed by any letter/numbers/underscore or a question mark (
?).
As with a real (spoken) language, every word has a specific meaning. And if you don't know the meaning of a word, you'll have to look it up in the dictionary. That's pretty much the way things work in Arturo as well.
In Arturo, a word may have 3 main different uses:
- refer to a value (that is: a variable, e.g.
x + 2) - refer to an action, which does something (that is: a function, e.g.
doSomething) - Arturo comes with hundreds already defined in its standard library - refer to nothing (that is: a word without meaning, as in the
[lorem ipsum]example above)
A label is nothing but Arturo's way of assigning meaning (to be read as a value) to a word - what you would normally call variable assignment or variable initialization. (In Arturo, these two terms can be used invariably, since there is practically no difference: you can set and re-define a word/variable as many times as you wish).
So, let's say you want to give a new meaning to the word x:
x: 2That was it: from now on, x will mean 2 (until and if it's changed). So if you follow the above statement with:
print x...Arturo will print 2 for you.
As the mere word says, symbols are used to symbolize something, mainly as an alias to an existing word - although, by convention, as infix operators.
Hence, let's take the function add. This takes two parameters, adds them up, and returns the result.
So, you may write:
print add 2 3and Arturo will print out 5 for you.
Now, if you don't want to use the add function (and prefix notation, which is the standard for all function calls), there is a symbol-alias for that: +
So, you could just as well write:
print 2 + 3Only, this time you're expressing it more like you would in a normal math expression: with infix notation.
Some of the existing aliases in the built-in dictionary:
%ALIAS_LIST%| Symbol | Aliased word |
|---|
All valid symbols:
<=, =>, <=>, <<=, =>>, <<=>>, <-, ->, <->, <<-, ->>, <<->>, -<, >-, >-<, -<<, >>-, >>-<<, <<, >>, <<<, >>>, <--, -->, <-->, <==, ==>, <==>, <~, ~>, <~>, |>, <|, <|>, =<, >=, <>, <:, -:, >:, ~, !, !!, ?, ??, @, #, ##, ###, ####, #####, ######, $, %, ^, &, *, **, -, --, =, ==, =~, +, ++, <, >, /, /%, //, \\, \\\\, |, |-, |=, .., ..., ./, :, ::, :=, ||, ∅, ∞, ∑, ∏, ∩, ∪, ⊂, ⊃, ⊆, ⊇, ∈, ∉, ∧, ∨, ⊻, ⊼, ¬
Another interesting feature of Arturo is what we'll analyze here: attributes.
Technically, attributes are nothing but an easy way of defining optional named parameters for functions - but which can however transcend between different function calls.
There are two types:
a. attributes
b. attribute labels
Attributes are actually optional on/off-type of values, set during a function call, that is there to denote some variation of the initial meaning of the function. To define an attribute, we'll be using a .(dot) followed by a normal word: \.\w+
Let's say we used the function split, to split a string into parts:
split "hello world"
; => [`h` `e` `l` `l` `o` ` ` `w` `o` `r` `l` `d` ]That does what it says: splits the string into an array of :chars.
What if we want for example to split the string into words? For that, there is the .words attribute for the function split. So:
split.words "hello world"
; = ["hello" "world"]💡 The order in which you pass the different attributes does not matter. Also, there is no issue at all whether you want to use spaces between them and the surrounding function call; Arturo will still be able to parse them and recognize them fine
Attribute labels are pretty much like simple attributes, only they can also take a value. As it worked with attributes, we'll be using a .(dot) followed by a normal word, but now also followed by a :(colon) -- exactly like with normal labels, as we've seen above.
Here's an example:
split .every: 2 "hello world"
; => ["he" "ll" "ow" "or" "ld"]Values are the very core of Arturo and are used to refer to pretty much all the different kinds of data you can have.
💡 Words, labels, and symbols - that we already saw above - can be considered "values" as well; and treated as such, unless we proceed to evaluate them!
We could split values into 2 categories: a) literal values - that is values you can directly define in your code and b) constructible - values that are created using some function.
The (hopefully) complete list follows.
Null values generally denote nothing and it's mostly used as a return value by functions to inform us that something went wrong. If you want to set it as a value, you may just use the word null, like:
x: nullLogicals are Arturo's logical values. They are like normal boolean values (true, false), with a twist: they fully support ternary logic and an additional maybe value.
x: true
y: false
z: maybeIntegers represent positive or negative integers. When they are declared they are comprised only by digits ([0-9]+) and they can be as long as you want - Arturo does support big numbers.
x: 2
y: 876528347613438247982374913423423947329Floating values are basically floating-point numbers, that is: decimals. They begin with an initial all-digit part, followed by a . (dot) and another all-digit part: [0-9]+\.[0-9]+
pi: 3.14159Even though there is no special syntax for defining a complex number, you can always create one using to. Arturo comes with full support for complex numbers and all the associated operations.
a: to :complex [1 2] ; a: 1.0+2.0i
b: to :complex @[pi pi] ; b: 3.141592653589793+3.141592653589793i
print a + b
; 4.141592653589793+5.141592653589793iThe syntax for rational literals is simply a number followed by a colon, followed by a number (pretty much like you would normally represent a ratio).
a: 1:2 ; 1/2
b: 3:4 ; 3/4As with complex numbers, rationals can also be defined using to. And again, Arturo comes with full support for rational numbers and all the associated operations.
a: to :rational [1 2] ; 1/2
b: to :rational [3 4] ; 3/4
print a + b
; 5/4Version values are nothing but a fancy and portable way of defining SemVer-compliant versions (e.g. for packaging an application). The rule is rather simple: it has three numeric parts, separated by a . (dot) and an optional part with build or prerelease information.
package: 1.0.3
if package > 1.0.0 -> print "yep, the version is right!"or
version: 1.2.3-rc1+build123Type is a value representing another... type. To specify a type value, the format is a : (colon) followed by a word - the type's name: :\w+
myType: :integeror
if (type x) = :integer [ print "it's an integer!" ]💡 If you want to define your own custom types (think "classes" in OOP languages), we have
definefor that: e.g.define :person [ init: method [name :string][ \name: name ] ] p: to :person ["John"]! print p\name ; John
Characters in Arturo can be declared using single quotes: '\w'
ch: 'a'A string is nothing but a series of characters, seen as one unit. In Arturo, to define a string, there are various ways:
Single-line strings
- using double quotes:
x: "this is a string"(with escaped characters) - using right smart-quote notation
x: « This is a string(in this case, everything following«till the end of the line, will be stripped and considered one string)
Multi-line strings
-
using curly-brace blocks (the result will be stripped and un-indented):
x: { this is yet another very long string that spans more than one line }
-
using verbatim curly-brace blocks (the result will remain exactly as-is):
x: {: this is yet another very long string that spans more than one line :}
-
using dash notation (where everything after the line, until the end of the file, is a string - stripped and un-indented):
x: ------ this is the last very long string that spans more than one line
💡 If you want your string to contain sub-expressions that will be evaluated on the fly - that is string interpolation - all you have to do is include your code inside the string within pipe-bars and then call the function
render(or~) to process it accordingly: e.g.x: 2 print ~"my variable is: |x|" ; prints: ; my variable is: 2
Arturo comes with full support of lazy ranges.
To create a range all you have to do is use the built-in range function (or its .. infix equivalent):
numbers: 1..10 ; contains all numbers from 1 to 10 (inclusive)
downwards: 10..1 ; this is valid as well
chars: 'a'..'z' ; yes, we can actually have character ranges tooRanges can be used in most functions as-is, e.g. Iterators, where we can take full advantage of their "lazy" nature: they are not evaluated until needed.
However, you can still evaluate a lazy range into its corresponding block any time you want:
@1..10 ; [1,2,3,4,5,6,7,8,9,10]A regex value is nothing but a string containing a regular expression (that is then compiled and treated as such).
The normal syntax is {/regex/}:
type {/[A-Z]/} ; => :regex
replace "HelLo" {/[A-Z]/} "X" ; here we replace all capital letters
; with an XWhile we may - optionally - use any of the supported PCRE-compliant flags:
i: case-insensitive matchingm: multilines: dot-all
match "Hello" {/he/i} ; => ["He"]Paths in Arturo are a way of defining some hierarchy between values, something along the lines of parent -> child -> grandchild. For this, in Arturo, we'd use a series of values or words delimited with a \ (backslash). You can think of them as indexes in other programming languages.
print user\nameor
x: "name"
print user\[x]or
myArray: ["zero" "one" "two" "three"]
print myArray\1
; prints "one"If paths are the way of defining some hierarchy between values, with pathLabels we are also able to assign values to some specific path.
user: #[
name: "John"
surname: "Doe"
]
print user\name ; will print "John"
; let's change this user's name
user\name: "Jane"
; we can also do it like that
x: "name"
user\[x]: "Jane"
print user\name ; ok, now it should print "Jane"💡 If you we are inside a custom type, an easy way to refer to fields of the same object is using
this. However, Arturo comes with a shortcut: e.g.define :person [ init: constructor [name :string] sayHello: method [][ print ["Hello" \name] ; this is equivalent to `this\name` ] ]which generally helps us write more better-looking code. :)
Literals in Arturo are just a way of referring to the name of a word or symbol. Think of it as the string version of a word, or like Ruby's symbols.
For example, the function info takes as an argument the name of the function for which you want some information. If you wrote like info print, the interpreter would execute the function print and try to... print something (which would not be there). If you wanted to refer to the name of the function -- that is: without actually calling it -- you would precede it with a ' (single-quote): '[\w+]
func: 'print
info funcHowever, literals may be used for much more - e.g. modifying a passed parameter in-place, without having to re-assign the result of an operation to a new variable. To learn more, have a look at In-place variable modification.
Symbol literals are to symbols pretty much what literals are to words. That is: the "literal", unevaluated form of the symbol.
To declare a symbol literal, we may follow the example of normal, literals: single quote + accompanied by the symbol in question:
type '++ ; => :symbolliteralNow, that we've seen both "normal" literals and paths, I guess you can already imagine what Path Literals are about... :)
And, yes, you guessed right:
type 'this\is\a\path ; => :pathliteralInlines in Arturo generally denote a list of words/symbols/values that are grouped and given some type of priority in evaluation. An inline block is denoted by (...) (parentheses).
print (2+3)*4Please note though that, apart from precedence, :inline is a value type on its own:
a: [(one) two three]
print type a\0 ; that is: (one)
; prints :inlineBlocks are a fundamental part of Arturo.
As we've already said, it's just a [...] (square-bracket enclosed) block of words/symbols/values that - in contrast with inline blocks above which are evaluated in-place - are not evaluated until it's necessary.
myBlock: [one two three]
anArray: [1 2 3 4 5]
anotherArray: ["zero" 1 "two" 3 "cuatro"]As you can see, blocks can contain practically anything: any word, any symbol, and any value. Of course, they can contain other blocks too:
x: [
1 2 [
3 4 [
5 "six" 7
]
8
]
9
]Dictionaries in Arturo as what in other languages you'd call an associative array or hash table. In Arturo, it's practically the same, only with an added twist: they are ordered hash tables.
If you want to create one, just give the dictionary function (or use the # alias) a block, with different labels, and it'll automatically convert it to a dictionary.
user: #[
name: "John"
surname: "Doe"
age: 34
]What the # function here does is:
- execute the block
- retrieve only the words/variables defined in there
- return a dictionary with the aforementioned words
💡 As you can probably assume from the above definition, a dictionary block doesn't necessarily have to contain just labels and word definitions - it may contain whatever you want, even function calls; only it will return you back just a table with the defined words in there
Now, that you've seen Dictionaries, imagine a dictionary that could actually save its contents to disk for every change you make to it. Or retrieve it from disk when you start your program again, offering you seamless integration with your data. And safety too.
Well, that's exactly what Stores are. :)
d: store "mystore" ; initialize your Store and
; specify where you want to store it
; (if the store already exists, it'll automatically load it)
d\name: "John" ; and you can use it as any normal dictionaryObject values are intimately related to custom types, as we have already seen above.
And while Arturo isn't properly speaking a primarily Object-oriented language, it offers more than enough functionality that will cover most OOP needs.
The normal way to create a new object, is by using to and a new custom type you have defined before:
newClient: to :person ["John" "Doe"]!
; yep, we've just created a new Object value!Technically, Objects are nothing but supercharged Dictionaries that come with a twist:
their functions (see: methods) can have access to its own fields and methods, from within - using this. But other than that, don't let them scare you out: it's just another tool in our toolkit! ;-)
Functions are another important value type in Arturo - and yes, you heard right: functions a value too. You can assign them to a word/variable, pass them around, re-define them and whatever you want with them, pretty much as you would do with another value, let's say a number.
To define a function, all you have to do is call the function... function (or use the $ alias) followed by two parameters:
- the parameters' names (this can be either a literal, e.g.
'x- if it's just one argument - or a block, e.g.[x y]. If you want to use commas, for readability, like[x,y]you are free to do so: Arturo will simply ignore them.
multiply: function [x y][
x * y
]
print multiply 2 3
; would print 6or
addThemUp: $[x,y][x+y]
print addThemUp 2 3
; would print 5Methods in Arturo are pretty much like functions. With a couple of asterisks:
- They are meant to be used only inside a custom type (in
define) or in amodulecontext - We'd use them only when we want to have access to
this(= in a few words, when we want to access other fields/functions/methods of the same object; if we don't need that, we could still use a function)
A quick example:
define :car [
init: method [; our constructor
brand :string
speed :quantity
][
this\brand: brand
this\speed: speed
]
distanceTravelled: method [inHours :quantity][
this\speed * inHours
]
]
myCar: to :car ["Volvo" 100`km/h]!
print ["In 2 hours, we'll have travelled:" myCar\distanceTravelled 2`h]We may also have magic methods, that is: making our custom types accessible-to or "overloading" normal stdlib methods.
For example, if we want to be able to print one of our custom objects, we'd first have to define a way that this custom object is meant to be converted to a string.
For that, we'd define a string magic method:
define :car [
; as previously
string: method [][
return "CAR :: " ++ \name
]
]
myCar: to :car ["Volvo C30" 100`km/h]!
print myCar ; this would print: CAR :: Volvo C30Supported Magic methods:
get: method [what] ; this\what
set: method [what, value] ; this\what: value
changing: method [] ; object about to change
changed: method [] ; object changed
compare: method [that] ; comparator definition (to compare between `this` and a second object)
equal?: method [that] ; this = that
less?: method [that] ; this < that
greater?: method [that] ; this > that
add: method [that] ; this + that
sub: method [that] ; this - that
mul: method [that] ; this * that
div: method [that] ; this / that
fdiv: method [that] ; this // that
mod: method [that] ; this % that
pow: method [that] ; this ^ that
inc: method [] ; inc this
dec: method [] ; dec this
neg: method [] ; neg this
key?: method [key] ; key? this key
contains?: method [field] ; contains? this field
append: method [what] ; this ++ what
remove: method [what] ; this -- what
string: method [] ; to :string this
integer: method [] ; to :integer this
floating: method [] ; to :floating this
rational: method [] ; to :rational this
complex: method [] ; to :complex this
quantity: method [] ; to :quantity this
logical: method [] ; to :logical this
block: method [] ; to :block this
dictionary: method [] ; to :dictionary this
Arturo has very advanced capabilities related to physical quantities, measurements and the related operations.
And everything begins with the concept of units.
To declare a Unit value, all you have to do is use a backtick, followed by the unit in question:
Meters: `m
SquareMeters: `m2
Becquerels: `BqThe list of builtin, supported Units is quite... long:
m, s, K, g, A, mol, cd, USD, B, rad, sr, in, ft, yd, ftm, rod, mi, fur, nmi, ang, au, ly, px, pt, pc, sqin, sqft, ac, are, ha, barn, L, gal, bbl, qt, p, cup, floz, tbsp, tsp, bu, cord, min, h, day, wk, mo, yr, lb, slug, oz, ct, t, ton, lt, st, Da, gr, dwt, ozt, lbt, mps, kph, mph, kn, fps, mach, Gal, N, dyn, lbf, kgf, pdl, Pa, atm, bar, pz, Ba, mmHg, psi, Torr, J, Wh, cal, BTU, eV, erg, th, thm, W, hp, statA, abA, Bi, V, statV, abV, Ohm, statOhm, abOhm, S, C, statC, abC, Fr, F, Daraf, H, abH, Wb, Mx, T, G, degC, degF, degR, b, KiB, MiB, GiB, TiB, PiB, EiB, deg, grad, arcmin, arcsec, kat, Hz, Bq, Ci, Gy, Sv, R, P, St, rpm, clo, bps, lx, Lb, lm
We also support most world currencies, with their ISO 3-letter code, e.g. USD, EUR, etc.
Compound units:
If you want to define compound units, Arturo actually supports that natively:
squareMeters: `m2
kilometersPerHours: `km/h
newtonDefinition: `kg.m/s2 ; yes, that's actually a N(ewton)Now, as we've seen, Arturo's Unit values are quite powerful. So, how can we express a Quantity using units?
Very simple: just add a number (a Rational literal works too) just in front of a unit:
twoMeters: 2`m ; yes, we've just expressed the notion of "2 meters"
; as a native Arturo valueAnd we can obviously use them in operations as every other value:
print 3`m + 4`yd ; 6.6576 m
And, yes, no need to worry about compatibility: Arturo actually understands dimensional analysis! ;-)
Colors can be easily defined using the #xxxxxx syntax, where xxxxxx is either the RGB value of the color in hex, or its common-name alias, like #red, #green or #blue:
color1: #red
color2: #0077BB
print color1 + color2Dates in Arturo are a distinct type of value. If you want to create one, you'll have to use one of the corresponding functions. For example, the function now returns a :date object, representing the current point in time. And it can be handled pretty much like you would handle a :dictionary.
print now
; would print 2020-10-26T10:27:14+01:00
print now\year
; would print 2020Database values cannot be constructed literally. However, using the function open, you can create a database value and then use it to query the database in question and much more.
db: open.sqlite "my.db"
print query db "SELECT * FROM users"
print type db ; would print: :databaseAnother not-literally constructible (but still powerful) value type is the Socket.
To use Socket values properly, just have a look into the Sockets library module.
If you want to create one, just have a look at the quick example below, using listen:
; start a server listening on port 18966
server: listen 18966 ; and, yes, that's a socket!Binary values are used to represent binary data, that is: an array of bytes. You cannot define them directly, however, you can sure convert other data to binary.
print to :binary "Hello world!"
; would print 4865 6C6C 6F20 776F 726C 6421Bytecode values cannot be constructed literally. However, you can create them indirectly, e.g. using the function to.
; let's create some Arturo bytecode from scratch
bcode: to :bytecode [
loop 1..10 'x [
print x
]
]
; and execute it!
do bcode
; we can also inspect it
inspect bcode
; [ :bytecode
; ================================
; DATA
; ================================
; 0: [ :block
; print :word
; x :word
; ]
; 1: x :literal
;
; ================================
; CODE
; ================================
; push0
; eol #4
; push1
; consti10
; consti1
; range
; loop
; end
; ]Here we are going to analyze a few aspects that make Arturo rather unique; or that - in any case - you should study a bit more in order to become a real... Arturo guru, in no time.
So, let's get started...
The easiest way to explain precedence rules in Arturo is pretty much like it happened with our introduction: there are no precedence rules whatsoever.
So, in an expression like 2 * 3 + 4, if you'd normally expect to get a result of 10, you would be wrong: the result is 14.
But in order to understand why, you'd have to understand how evaluation in Arturo works.
The main expression evaluation order of Arturo is right-to-left. But with a tiny asterisk: Your code will be evaluated from left to right, it is the expressions passed to your function calls that will be evaluated from right-to-left.
Let's take a very simple example:
print add 1 2
print "Done"As you would expect, the first function to be executed is the first print function and then the second one. Nothing new here.
Now let's take the first print. How is it working?
Let's see:
- First, the value
2is pushed onto the stack - Then, we push the value
1 - Then, we execute the function
add: it pops two values from the stack, adds them up, and pushes the result (3) back onto the stack - Finally, we execute the function
print: it pops the top value from the stack (3) and prints it.
Then, execution would move on and... print "Done."
What you have to understand here is that evaluation within an expression will always be done from right to left, irrespective of what you might know from other languages or math operator precedence. In Arturo, you have to learn no precedence rules at all. You'll just have to remember to always calculate from right to left.
Re-visiting our previous, seemingly paradoxical, example:
2 * 3 + 4💡 Remember: our
+and*operators are nothing but simple infix aliases to the functionsaddandmulrespectively -- nothing more!
This is as if we had written (moving the operators in front):
* 2 + 3 4which practically means: FIRST add 3 and 4 and THEN take the result and multiply it with 2.
If this is not what intended, then the right way in Arturo would be, either:
4 + 2 * 3or (giving precedence to the multiplication, artificially, using parentheses):
(2 * 3) + 4Another example:
Let's say we want to concatenate a number and a string into a new string.
to :string 3 ++ " <-- this is our number"The above example wouldn't work, because first it tries to concatenate 3 with a string (" <-- this is our number) and then performs to :string.
While what we actually want is to first convert our number to a string and then concatenate the two strings.
The correct code in that case would be:
(to :string 3) ++ " <-- this is our number"Contrary to what you might expect, Arturo doesn't feature a traditional concept of scope. There are no real local or global variables, no local or global functions, no local or global blocks, no local or global anything.
Generally, if a variable has been previously declared at the moment and location of its usage, then it is available. Otherwise, it is not.
But let's see a couple of concrete cases to make this clearer.
Arturo doesn't have a block scope.
In a few words, this means:
- A variable declared inside a block is available outside of it
- A variable previously declared outside of a block is available inside
- The changes of an existing variable, inside a block, persist after the block
x: 1 ; here, we declare a variable x
; and set it to 1
do [
x: 2 ; here, we re-assign the value of x
; to 2
print x ; prints 2
y: 3 ; here, we declare a variable y
; and set it to 3
]
print x ; prints 2 (the value of x has been changed)
print y ; prints 3 (the value of y is still available)Iterators (such as loop, map, etc) always work with a block as well. But in a special way.
Basically, the logic is identical to the one of blocks, but with a slight difference:
- the injected variables (e.g. the iteration arguments), are available only inside the block, but not after the iteration is over
- any previous value is "protected" and restored if needed
x: 3
loop.with:'i ["one" "two" "three"] 'x [
print i ; prints 0, 1, 2,...
print x ; prints "one", "two", "three",...
]
print x ; prints 3 (the value of x has been restored)
print i ; ERROR: variable not found
; (i is not available anymore)Functions are totally different. Why? Because they do have their own scope.
The general idea is:
- A variable declared inside a function is available only inside the function
- A variable previously declared outside of a function is available inside
- The changes of an existing variable, inside a function, do not persist after the function
If we want to export a specific symbol to the outer scope, that is, make it available outside the function, we can use the .export: attribute.
If we want to export all of the symbols - thus, practically making the function scope-less, we may use the .inline attribute.
In Arturo, every time you pass a parameter to a function, you can rest assured that the value of that parameter won't change (unless it's a string, block or dictionary and you - consciously - decided to use set on it, in which case it does alter its inner structure).
So, basically, you when do this...
a: [1 5 2 4 3]
sort a...all you do is to take an array, sort it, and push the sorted array onto the stack. Variable a simply does not change.
So, what would you do if you wanted to get the array back, but sorted?
The simple - and most obvious - way would be to re-assign the returned result from sort:
a: [1 5 2 4 3]
a: sort aAnd now, yes, a does contain the sorted version of the initial array.
But, what if you want to perform the modification in-place, which is normally faster and without the need for intermediate variables? Literals come to the rescue!
As we've already said, "literals" ('i 'am 'a 'literal) are nothing but string representations of a word, that is... the word itself. For that reason, they may come in very handy when you want to modify a variable in-place.
Let's revisit the above example and what the syntax of sort is:
sort collection :literal :dictionary :blockAs we can see, sort takes one parameter (collection) which is either a :dictionary or :block OR a :literal.
Why pass a literal? Simply because this turns in-place modification on! Let's have a look:
a: [1 5 2 4 3]
sort 'a ; yep, now a *has* been sorted in-place!And this is very powerful: in Arturo, most of the built-in functions in the library come with this feature included. Practically, whenever you see a function taking a literal first parameter, that means you can use it for in-place modifying a variable (yes, even add works like that!).
⚠️ Word of caution: Values in Arturo are always passed by reference - unless they are constant/readonly values. So if you want to assign one variable to another and then modify one of them in-place, make sure you usenew; otherwise, both values will change!a: 1 b: a inc 'a ; both a and b are now 2 c: 1 d: new c ; we copy the value of c into d inc 'c ; now c is 2 and d is 1, as expected
As you have hopefully seen so far, Arturo is rather simple, with fairly simple rules and that's pretty much it.
However, we also have some "syntactic sugar": a fancy way of referring to syntactic constructs, so that something more complicated will look better, or easier-to-write, or more readable.
Here you'll learn about some useful examples of syntactic sugar supported in Arturo.
The function of the right operator is rather straightforward: basically, it wraps the following terminal value inside a block.
Let's take a simple example.
x: -> 2This is 100% equivalent to:
x: [2]You can also use the right-arrow operator to make many common constructs far more readable.
For example:
if x=2 -> print "x was 2!"is the same as writing:
if x=2 [ print "x was 2!" ]As you can see, it can be pretty handy. Just remember that -> can wrap only one terminal value.
For example:
x: -> 2 3This doesn't result in x: [2 3] but in x: [2] 3
Another interesting way of making use of the power of the right-arrow operator:
loop 1..10 'x -> print xwhich is the same as writing (only much more elegant):
loop 1..10 'x [ print x ]The fat right-arrow operator is like a super-charged simple right arrow operator (->) as described above.
If -> was used to wrap the following terminal into a block, the => operator does even more.
Let's take this simple example:
x: $ => addThis is equivalent to writing:
x: $[x,y][add x y]Basically, it reads the following word, and if it's a function, pushes all its needed arguments as anonymous variables.
The same could work with a block argument, where & can be used as a placeholder for the needed anonymous variables:
x: $ => [add & &](The first & will pop the first argument, and the second the next one - and so on...)
As you can already imagine, this is perfect for easily defining functions or action blocks that take exactly one parameter.
For example, to print an array of the even numbers between 1 and 10:
print select 1..10 'x [even? x]This could be easily written as (using the -> operator):
print select 1..10 'x -> even? xBut pushing the limits more, we can also use the => operator:
print select 1..10 => even?That's surely much more readable, isn't it?
The double-colon operator does something very simple: it wraps everything in a block - until the end of... the current block:
do [
print ::
"This is a number:"
123
]Is equivalent to:
do [
print ["This is a number:" 123]
]Explaining the exclamation-mark can be a bit tricky, but if you want the short version:
it wraps everything that follows in a do block (more or less).
Or the shorter version:
- Have you just created a new custom-type object? (e.g.
to :myObject [])? - Have you imported an external package? (e.g.
import 'somePackage)?
Then just put ! at the end of the statement (e.g. import 'somePackage!) and everything will work as you expect.
The long explanation:
Arturo, when parsing a block of code, has to know which symbols correspond to function calls and how many arguments they take. The exact same is valid for object methods.
When we create a new object (e.g. p: to :person ["John"]), if we attempt to use p\someMethod from the exact same block where this p value was initialized, there is no possible way to know beforehand that e.g. someMethod is a method. We'll know that only after to :person ["John"] has been executed. But then, it's already too late. So, how do we make sure that Arturo knows about the object before we attempt to call inner methods? By putting a "stopper" after the object creation, and that stopper is our beloved... !.
💡 Technically we could achieve the same thing without the
!sugar:p: to :person ["John"] do [ p\sayHello ]That would work too, for all practical purposes. But:
!is looking good. And it's also far more performant, based on the way it's implemented internally! ;-)
⚠️ This is experimental and may still not be stable enough for use in production scripts
The pipe operator is an easy way of reversing the default prefix notation of function calls and simulating what in OOP languages is called function chain.
Let's take this simple example:
1..10 | printThis equivalent to:
print 1..10Or a bit more elaborate example (using pipes and the ->/=> operators):
1..10 | map => [2 * &]
| select 'x -> even? x
| printwhich would be like writing:
print select map 1..10 'x [2*x] 'x [even? x] If you made it here, then I can assure you: you've already learned more than you need in order to be fully proficient in Arturo.
Just head to the Library Reference and have a look at the built-in functions (with explanations and example code) and see what's already available for you or - if you want to see the language in action - just browse through the Examples: there are many (many!) working examples, to get more than just an idea.
Welcome on board! :)
This section is inspired by Learn X in Y minutes and its goal is to present the most basic features of Arturo, in a concise way, so that you can get started fast.
So... With X = Arturo and Y = ~15 minutes, here you are:
; this is a comment
; this is another comment
;---------------------------------
; VARIABLES & VALUES
;---------------------------------
; numbers
a1: 2
a2: 3.14
a3: to :complex [1 2.0] ; 1.0+2.0i
; strings
c1: "this is a string"
c2: {
this is a multiline string
that is indentation-agnostic
}
c3: {:
this is
a verbatim
multiline string
which will remain exactly
as the original
:}
; characters
ch: 'c'
; blocks/arrays
d: [1 2 3]
; dictionaries
e: #[
name: "John"
surname: "Doe"
age: 34
likes: [pizza spaghetti]
]
; yes, functions are values too
f: function [x][
2 * x
]
; colors - right, you can directly define them as well!
g1: #red
g2: #0077BF
; dates
h: now ; 2021-05-03T17:10:48+02:00
; versions
currentVersion: 3.2.10-beta ; SemVer compatible :)
; logical values
i1: true
i2: false
i3: maybe
; units
meters: `m
kilograms: `kg
; quantities
height: 3`yd
width: 4`m
;---------------------------------
; BASIC OPERATORS
;---------------------------------
; simple arithmetic
1 + 1 ; => 2
8 - 1 ; => 7
4.2 - 1.1 ; => 3.1
10 * 2 ; => 20
35 / 4 ; => 8
35 // 4 ; => 8.75
2 ^ 5 ; => 32
5 % 3 ; => 2
; bitwise operators
and 3 5 ; => 1
or 3 5 ; => 7
xor 3 5 ; => 6
; pre-defined constants
pi ; => 3.141592653589793
epsilon ; => 2.718281828459045
null ; => null
true ; => true
false ; => false
;---------------------------------
; COMPARISON OPERATORS
;---------------------------------
; equality
1 = 1 ; => true
2 = 1 ; => false
; inequality
1 <> 1 ; => false
2 <> 1 ; => true
; more comparisons
1 < 10 ; => true
1 =< 10 ; => true
10 =< 10 ; => true
1 > 10 ; => false
1 >= 10 ; => false
11 >= 10 ; => true
;---------------------------------
; CONDITIONALS
;---------------------------------
; logical operators
and? true true ; => true
and? true false ; => false
or? true false ; => true
or? false false ; => false
and? [1=2][2<3] ; => false
; (the second block will not be evaluated)
; simple if statements
if 2 > 1 [ print "yes!"] ; yes!
if 3 <> 2 -> print "true!" ; true!
; switch statements
switch 2 > 3 -> print "2 is greater than 3"
-> print "2 is not greater than 3" ; 2 is not greater than 3
a: (2 > 3)?["yes"]["no"] ; a: "no"
a: (2 > 3)? -> "yes" -> "no" ; a: "no" (exactly the same as above)
; case statements
key: "one"
case key [ ; the main block is always evaluated!
"one" -> print "key is one!"
"two" -> print "key is two!"
any -> print "key is none of the above"
]
; when statements
when [ ; the main block is always evaluated!
prime? 4 -> print "yes, 4 is prime - wait, what?!"
prime? 5 -> print "yes, 5 is prime
prime? 7 -> print "yes, 6 is prime
true -> print "none of the above was true"
]
; yes, 5 is prime
when.any [ ; cascade-style checking (without breaking)
prime? 4 -> print "yes, 4 is prime - wait, what?!"
prime? 5 -> print "yes, 5 is prime"
prime? 7 -> print "yes, 7 is prime"
]
; yes, 5 is prime
; yes, 7 is prime
x: 2
when.has: x [ ; prepends passed parameter to each block/condition
[=0] -> print "x is zero!"
[<1] -> print "x is less than 1"
[<4] -> print "x is less than 4"
true -> print "x is >= 4"
]
; x is less than 4
;---------------------------------
; LOOPS
;---------------------------------
; with `loop`
arr: [1 4 5 3]
loop arr 'x [
print ["x =" x]
]
; x = 1
; x = 4
; x = 5
; x = 3
; with loop and custom index
loop.with:'i arr 'x [
print ["item at position" i "=>" x]
]
; item at position 0 => 1
; item at position 1 => 4
; item at position 2 => 5
; item at position 3 => 3
; using ranges
loop 1..3 'x -> ; since it's a single statement
print x ; there's no need for [block] notation
; we can wrap it up using the `->` syntactic sugar
loop 'a'..'c' 'ch ->
print ch
; a
; b
; c
; picking multiple items
loop 1..10 [x y] ->
print ["x =" x ", y =" y]
; x = 1 , y = 2
; x = 3 , y = 4
; x = 5 , y = 6
; x = 7 , y = 8
; x = 9 , y = 10
; looping through a dictionary
dict: #[name: "John", surname: "Doe", age: 34]
loop dict [key value][
print [key "->" value]
]
; name -> John
; surname -> Doe
; age -> 34
; while loops
i: 0
while [i<3][
print ["i =" i]
inc 'i
]
; i = 0
; i = 1
; i = 2
;---------------------------------
; STRINGS
;---------------------------------
; case
a: "tHis Is a stRinG"
print upper a ; THIS IS A STRING
print lower a ; this is a string
print capitalize a ; THis Is a stRinG
; concatenation
a: "Hello " ++ "World!" ; a: "Hello World!"
; strings as an array
split "hello" ; => [h e l l o]
split.words "hello world" ; => [hello world]
print first "hello" ; h
print last "hello" ; o
; conversion
to :string 123 ; => "123"
to :integer "123" ; => 123
; joining strings together
join ["hello" "world"] ; => "helloworld"
join.with:"-" ["hello" "world"] ; => "hello-world"
; string interpolation
x: 2
print ~"x = |x|" ; x = 2
; interpolation with `print`
print ["x =" x] ; x = 2
; (`print` works by calculating the given block
; and joining the different values as strings
; with a single space between them)
; templates
print render.template {
<||= switch x=2 [ ||>
Yes, x = 2
<||][||>
No, x is not 2
<||]||>
} ; Yes, x = 2
; matching
prefix? "hello" "he" ; => true
suffix? "hello" "he" ; => false
contains? "hello" "ll" ; => true
contains? "hello" "he" ; => true
contains? "hello" "x" ; => false
in? "ll" "hello" ; => true
in? "x" "hello" ; => false
;---------------------------------
; BLOCKS
;---------------------------------
; calculate a block
arr: [1 1+1 1+1+1]
@arr ; => [1 2 3]
; execute a block
sth: [print "Hello world"] ; this is perfectly valid,
; could contain *anything*
; and will not be executed...
do sth ; Hello world
; (...until we tell it to)
; array indexing
arr: ["zero" "one" "two" "three"]
print first arr ; zero
print arr\0 ; zero
print last arr ; three
print arr\3 ; three
x: 2
print get arr x ; two
print arr\[x] ; two
; setting an array element
arr\0: "nada"
set arr 2 "dos"
print arr ; nada one dos three
z: 2
arr\[z]: "dos" ; would have the same effect
; adding elements to an array
arr: []
'arr ++ "one"
'arr ++ "two"
print arr ; one two
; remove elements from an array
arr: ["one" "two" "three" "four"]
'arr -- "two" ; arr: ["one" "three" "four"]
remove 'arr .index 0 ; arr: ["three" "four"]
; getting the size of an array
arr: ["one" 2 "three" 4]
print size arr ; 4
; getting a slice of an array
print slice ["one" "two" "three" "four"] 0 1 ; one two
; check if array contains a specific element
print contains? arr "one" ; true
print contains? arr "five" ; false
; sorting array
arr: [1 5 3 2 4]
sort arr ; => [1 2 3 4 5]
sort.descending arr ; => [5 4 3 2 1]
; mapping values
map 1..10 [x][2*x] ; => [2 4 6 8 10 12 14 16 18 20]
map 1..10 'x -> 2*x ; same as above
map 1..10 => [2 * &] ; same as above
map 1..10 => [2*] ; same as above
; selecting/filtering array values
select 1..10 [x][odd? x] ; => [1 3 5 7 9]
select 1..10 => odd? ; same as above
filter 1..10 => odd? ; => [2 4 6 8 10]
; (now, we leave out all odd numbers -
; while select keeps them)
; misc operations
arr: ["one" 2 "three" 4]
reverse arr ; => [4 "three" 2 "one"]
shuffle arr ; => [2 4 "three" "one"]
unique [1 2 3 2 3 1] ; => [1 2 3]
permutate [1 2 3] ; => [[1 2 3] [1 3 2] [3 1 2] [2 1 3] [2 3 1] [3 2 1]]
take 1..10 3 ; => [1 2 3]
repeat [1 2] 3 ; => [1 2 1 2 1 2]
;---------------------------------
; FUNCTIONS
;---------------------------------
; declaring a function
f: function [x][ 2*x ]
f: function [x]-> 2*x ; same as above
f: $[x]->2*x ; same as above (only using the `$` alias
; for the `function`... function)
; calling a function
f 10 ; => 20
; returning a value
g: function [x][
if x < 2 -> return 0
res: 0
loop 0..x 'z [
res: res + z
]
return res
]
;---------------------------------
; CUSTOM TYPES
;---------------------------------
; defining a custom type
define :person [
; define a new custom type "Person"
; with fields: name, surname, age
init: method [name surname age][
\name: capitalize name
\surname: surname
\age: age
]
; custom print function
string: method [][
render "NAME: |\name|, SURNAME: |\surname|, AGE: |\age|"
]
; custom comparison operator
compare: sortable 'age
]
; create a method for our custom type
sayHello: function [this :person][
print ["Hello" this\name]
]
; create new objects of our custom type
a: to :person ["John" "Doe" 34]! ; let's create 2 "Person"s
b: to :person ["jane" "Doe" 33]! ; and another one
; call pseudo-inner method
sayHello a ; Hello John
sayHello b ; Hello Jane
; access object fields
print ["The first person's name is:" a\name] ; The first person's name is: John
print ["The second person's name is:" b\name] ; The second person's name is: Jane
; changing object fields
a\name: "Bob"
sayHello a ; Hello Bob
; verifying object type
print type a ; :person
print is? :person a ; true
; printing objects
print a ; NAME: Bob, SURNAME: Doe, AGE: 34
; sorting user objects (using custom comparator)
print sort @[a b] ; Jane..., Bob...
print sort.descending @[a b] ; Bob..., Jane... Basic arithmetic operations (addition, subtraction, multiplication, etc) for integers and floating-point numbers
add given values and return result
valueA(:integer,:floating,:complex,:rational,:literal,:pathliteral,:quantity,:color,:object)valueB(:integer,:floating,:complex,:rational,:quantity,:color,:object)
:integer,:floating,:complex,:rational,:quantity,:color,:object,:nothing
decrease given value by 1
value(:integer,:floating,:complex,:rational,:literal,:pathliteral,:quantity,:object)
:integer,:floating,:complex,:rational,:quantity,:object,:nothing
perform integer division between given values and return result
valueA(:integer,:floating,:complex,:rational,:literal,:pathliteral,:quantity,:object)valueB(:integer,:floating,:complex,:rational,:quantity,:object)
:integer,:floating,:complex,:rational,:quantity,:object,:nothing
perform integer division between given values and return tuple with quotient and remainder
valueA(:integer,:floating,:complex,:rational,:literal,:pathliteral,:quantity)valueB(:integer,:floating,:complex,:rational,:quantity)
:block,:nothing
divide given values and return result
valueA(:integer,:floating,:rational,:literal,:pathliteral,:quantity,:object)valueB(:integer,:floating,:rational,:quantity)
:floating,:rational,:quantity,:object,:nothing
increase given value by 1
value(:integer,:floating,:complex,:rational,:literal,:pathliteral,:quantity,:object)
:integer,:floating,:complex,:rational,:quantity,:object,:nothing
calculate the modulo of given values and return result
valueA(:integer,:floating,:rational,:literal,:pathliteral,:quantity,:object)valueB(:integer,:floating,:rational,:quantity)
:integer,:floating,:rational,:quantity,:object,:nothing
calculate the product of given values and return result
valueA(:integer,:floating,:complex,:rational,:literal,:pathliteral,:quantity,:object)valueB(:integer,:floating,:complex,:rational,:quantity,:object)
:integer,:floating,:complex,:rational,:quantity,:object,:nothing
reverse sign of given value and return it
value(:integer,:floating,:complex,:rational,:literal,:pathliteral,:quantity,:object)
:integer,:floating,:complex,:rational,:quantity,:object,:nothing
calculate the power of given values and return result
valueA(:integer,:floating,:complex,:rational,:literal,:pathliteral,:quantity,:object)valueB(:integer,:floating)
:integer,:floating,:complex,:rational,:quantity,:object,:nothing
subtract given values and return result
valueA(:integer,:floating,:complex,:rational,:literal,:pathliteral,:quantity,:color,:object)valueB(:integer,:floating,:complex,:rational,:quantity,:color,:object)
:integer,:floating,:complex,:rational,:quantity,:color,:object,:nothing
Bit manipulation methods & bitwise operators (AND, OR, XOR, etc) for integer values
calculate the binary AND for the given values
valueA(:integer,:literal,:pathliteral,:binary)valueB(:integer,:binary)
:integer,:binary,:nothing
calculate the binary NAND for the given values
valueA(:integer,:literal,:pathliteral,:binary)valueB(:integer,:binary)
:integer,:binary,:nothing
calculate the binary NOR for the given values
valueA(:integer,:literal,:pathliteral,:binary)valueB(:integer,:binary)
:integer,:binary,:nothing
calculate the binary complement the given value
value(:integer,:literal,:pathliteral,:binary)
:integer,:binary,:nothing
calculate the binary OR for the given values
valueA(:integer,:literal,:pathliteral,:binary)valueB(:integer,:binary)
:integer,:binary,:nothing
shift-left first value bits by second value
value(:integer,:literal,:pathliteral)bits(:integer)
safe(:logical): check for overflows
:integer,:nothing
shift-right first value bits by second value
value(:integer,:literal,:pathliteral)bits(:integer)
:integer,:nothing
calculate the binary XNOR for the given values
valueA(:integer,:literal,:pathliteral,:binary)valueB(:integer,:binary)
:integer,:binary,:nothing
calculate the binary XOR for the given values
valueA(:integer,:literal,:pathliteral,:binary)valueB(:integer,:binary)
:integer,:binary,:nothing
Functions and helpers for manipulating and dealing with different types of collections (blocks, dictionaries, and strings)
append value to given collection
collection(:char,:string,:literal,:pathliteral,:binary,:object,:block)value(:any)
:string,:binary,:object,:block,:nothing
create array from given block, by reducing/calculating all internal values
source(:any)
of(:integer,:block): initialize an empty n-dimensional array with given dimensions
:block
remove last item from given collection
collection(:string,:literal,:pathliteral,:block)
times(:integer): remove multiple items
:string,:block,:nothing
get all possible combinations of the elements in given collection
collection(:block)
by(:integer): define size of each setrepeated(:logical): allow for combinations with repeated elementscount(:logical): just count the number of combinations
:integer,:block
check if collection contains given value
collection(:string,:dictionary,:object,:block,:range)value(:any)
at(:integer): check at given location within collectiondeep(:logical): searches recursively in deep for a value.
:logical
get combination of elements in given collections as array of tuples
collectionA(:block)collectionB(:block)
:block
get tuple of collections from a coupled collection of tuples
collection(:literal,:pathliteral,:block)
:block
create dictionary from given block or file, by getting all internal symbols
source(:string,:block)
with(:block): embed given symbolsraw(:logical): create dictionary from raw blocklower(:logical): automatically convert all keys to lowercase
:dictionary
remove first item from given collection
collection(:string,:literal,:pathliteral,:block)
times(:integer): remove multiple items
:string,:block,:nothing
empty given collection
collection(:literal,:pathliteral)
:nothing
check if given collection is empty
collection(:null,:string,:dictionary,:block)
:logical
get new dictionary by merging given ones
parent(:literal,:pathliteral,:dictionary)additional(:dictionary)
:dictionary
return the first item of the given collection
collection(:string,:block,:range)
n(:integer): get first n items
:null,:any
flatten given collection by eliminating nested blocks
collection(:literal,:pathliteral,:block)
once(:logical): do not perform recursive flattening
:block
get collection's item by given index
collection(:complex,:string,:error,:errorkind,:date,:binary,:dictionary,:object,:store,:block,:range,:bytecode)index(:any)
:any
check if value exists in given collection
value(:any)collection(:string,:dictionary,:object,:block,:range)
at(:integer): check at given location within collectiondeep(:logical): searches recursively in deep for a value.
:logical
return first index of value in given collection
collection(:string,:dictionary,:block,:range)value(:any)
:null,:integer,:string
insert value in collection at given index
collection(:string,:literal,:pathliteral,:dictionary,:block)index(:integer,:string)value(:any)
:string,:dictionary,:block,:nothing
check if collection contains given key
collection(:dictionary,:object)key(:any)
:logical
get list of keys for given collection
dictionary(:dictionary,:object)
:block
return the last item of the given collection
collection(:string,:block,:range)
n(:integer): get last n items
:null,:any
get maximum element in given collection
collection(:block,:range)
index(:logical): retrieve index of maximum element
:null,:any
get minimum element in given collection
collection(:block,:range)
index(:logical): retrieve index of minimum element
:null,:any
check if given number or collection size is one
number(:null,:integer,:floating,:string,:dictionary,:block,:range)
:logical
get all possible permutations of the elements in given collection
collection(:block)
by(:integer): define size of each setrepeated(:logical): allow for permutations with repeated elementscount(:logical): just count the number of permutations
:block
remove and return the last item from given collection
collection(:literal,:pathliteral)
n(:integer): remove multiple items. (Must be greater than 0.)
:any
prepend value to given collection
collection(:char,:string,:literal,:pathliteral,:binary,:block)value(:any)
:string,:binary,:block,:nothing
get list of values in given range (inclusive)
from(:integer,:char)to(:integer,:floating,:char)
step(:integer): use step between range values
:range
remove value from given collection
collection(:string,:literal,:pathliteral,:dictionary,:object,:block)value(:any)
key(:logical): remove dictionary keyonce(:logical): remove only first occurenceindex(:logical): remove specific indexprefix(:logical): remove first matching prefix from stringsuffix(:logical): remove first matching suffix from stringinstance(:logical): remove an instance of a block, instead of its elements.
:string,:dictionary,:block,:nothing
repeat value the given number of times and return new one
value(:literal,:pathliteral,:any)times(:integer)
:string,:block
reverse given collection
collection(:string,:literal,:pathliteral,:block,:range)
exact(:logical): make sure the reverse range contains the same elements
:string,:block,:nothing
right-rotate collection by given distance
collection(:string,:literal,:pathliteral,:block)distance(:integer)
left(:logical): left rotation
:string,:block,:nothing
get a random element from given collection
collection(:block,:range)
:null,:any
set collection's item at index to given value
collection(:string,:binary,:dictionary,:object,:store,:block,:bytecode)index(:any)value(:any)
:nothing
get given collection shuffled
collection(:literal,:pathliteral,:block)
:block,:nothing
get size/length of given collection
collection(:null,:string,:binary,:dictionary,:object,:block,:range)
:integer,:floating
get a slice of collection between given indices
collection(:string,:literal,:pathliteral,:block)from(:integer)to(:integer)
:string,:block
sort given block in ascending order
collection(:literal,:pathliteral,:dictionary,:block)
as(:literal): localized by ISO 639-1 language codesensitive(:logical): case-sensitive sortingdescending(:logical): sort in descending ordervalues(:logical): sort dictionary by valuesby(:string,:literal): sort array of dictionaries by given key
:block,:nothing
check if given collection is already sorted
collection(:block)
descending(:logical): check for sorting in ascending order
:logical
split collection to components
collection(:string,:literal,:pathliteral,:block)
words(:logical): split string by whitespacelines(:logical): split string by linesby(:string,:regex,:block): split using given separatorat(:integer): split collection at given positionevery(:integer): split collection every n elementspath(:logical): split path components in string
:block,:nothing
reduce adjacent elements in given collection
collection(:string,:literal,:pathliteral,:block)
:string,:block,:nothing
keep first of elements from given collection and return the remaining ones
collection(:string,:literal,:pathliteral,:block,:range)number(:integer)
:string,:block,:nothing
find number of occurences of each value within given block and return as dictionary
collection(:string,:block)
:dictionary
get given collection without duplicates
collection(:string,:literal,:pathliteral,:block)
id(:logical): generate unique id using given prefix
:block,:nothing
get list of values for given collection
dictionary(:dictionary,:object,:block,:range)
:block
check if given number or collection size is zero
number(:null,:integer,:floating,:string,:dictionary,:block,:range)
:logical
Functions and helpers for manipulating color values
blend given colors and get result
colorA(:literal,:pathliteral,:color)colorB(:color)
balance(:floating): use different mix of color (0.0-1.0, default:0.5)
:color
darken color by given percentage (0.0-1.0)
color(:literal,:pathliteral,:color)percent(:floating)
:color
desaturate color by given percentage (0.0-1.0)
color(:literal,:pathliteral,:color)percent(:floating)
:color
convert color to grayscale
color(:literal,:pathliteral,:color)
:color
get complement for given color
color(:literal,:pathliteral,:color)
:color
lighten color by given percentage (0.0-1.0)
color(:literal,:pathliteral,:color)percent(:floating)
:color
create palette using given base color
color(:color)
triad(:logical): generate a triad palettetetrad(:logical): generate a tetrad palettesplit(:logical): generate a split complement paletteanalogous(:logical): generate an analogous palettemonochrome(:logical): generate a monochromatic paletterandom(:logical): generate random palette based on color triadssize(:integer): specify the size of the generated palette
:block
saturate color by given percentage (0.0-1.0)
color(:literal,:pathliteral,:color)percent(:floating)
:color
spin color around the hue wheel by given amount
color(:literal,:pathliteral,:color)amount(:integer)
:color
Comparison operations for any kind of value
check if given value is between the given values (inclusive)
value(:any)rangeFrom(:any)rangeTo(:any)
:logical
compare given values and return -1, 0, or 1 based on the result
valueA(:any)valueB(:any)
:integer
check if valueA = valueB (equality)
valueA(:any)valueB(:any)
:logical
check if valueA > valueB (greater than)
valueA(:any)valueB(:any)
:logical
check if valueA >= valueB (greater than or equal)
valueA(:any)valueB(:any)
:logical
check if valueA < valueB (less than)
valueA(:any)valueB(:any)
:logical
check if valueA =< valueB (less than or equal)
valueA(:any)valueB(:any)
:logical
check if valueA <> valueB (not equal)
valueA(:any)valueB(:any)
:logical
check if given values are exactly the same (identity)
valueA(:any)valueB(:any)
:logical
Functions and helpers to create common objects (functions, arrays, dictionaries) and utilities for converting between different types and formats
format given value as implied type
value(:any)
binary(:logical): format integer as binaryhex(:logical): format integer as hexadecimaloctal(:logical): format integer as octalagnostic(:logical): convert words in block to literals, if not in contextdata(:logical): parse input as Arturo data blockcode(:logical): convert value to valid Arturo codepretty(:logical): prettify generated codeunwrapped(:logical): omit external block notation
:any
get value from string, using given representation
value(:string,:literal)
binary(:logical): get integer from binary representationhex(:logical): get integer from hexadecimal representationoctal(:logical): get integer from octal representationopcode(:logical): get opcode by from opcode literal
:any
Basic functions and constants that make up the very core of the language
assign symbol to given function
symbol(:string,:symbol,:symbolliteral,:block)function(:string,:word,:literal)
infix(:logical): use infix precedence
:nothing
the ANY constant
break out of current block or loop
:nothing
call function with given list of parameters
function(:string,:word,:literal,:pathliteral,:function,:method)params(:block)
external(:string): path to external libraryexpect(:type): expect given return type
:any
match given argument against different values and execute corresponding block
argument(:any)matches(:dictionary,:block)
:logical
if first value is null or false, return second value; otherwise return the first one
value(:any)alternative(:any)
:any
immediately continue with next iteration
:nothing
discard given value, without pushing it onto the stack
value(:any)
:nothing
evaluate and execute given code
code(:string,:block,:bytecode)
times(:integer): repeat block execution given number of times
:any
duplicate the top of the stack and convert non-returning call to a do-return call
value(:any)
:any
perform action, if last condition was not true
otherwise(:block,:bytecode)
:nothing
assert given condition is true, or exit
condition(:block)
that(:string): prints a custom message when ensure fails
:nothing
export given container children to current scope
module(:dictionary,:object,:module)
all(:logical): export everything, regardless of whether it's been marked as public (makes sense only for modules)
:nothing
create function with given arguments and body
arguments(:literal,:block)body(:block)
import(:block): import/embed given list of symbols from current environmentexport(:block): export given symbols to parentmemoize(:logical): store results of function callsinline(:logical): execute function without scope
:function
perform action, if given condition is not false or null
condition(:any)action(:block,:bytecode)
:nothing
perform action, if given condition is not false or null and return condition result
condition(:any)action(:block)
:logical
import given package
package(:string,:literal,:block)
version(:version): specify package versionmin(:logical): get any version >= the specified onebranch(:string,:literal): use specific branch for repository url (default: main)latest(:logical): always check for the latest version availablelean(:logical): return as a dictionary, instead of importing in main namespaceonly(:block): import only selected symbols, if availableverbose(:logical): output extra information
:dictionary,:block,:nothing
set symbol to given value
symbol(:string,:word,:literal,:block)value(:any)
:nothing
create type method with given arguments and body
arguments(:literal,:block)body(:block)
distinct(:logical): shouldn't be treated as a magic methodpublic(:logical): make method public (relevant only in modules!)
:method
create new module with given contents
contents(:dictionary,:block)
with(:block): use given initialization parameters
:module
create new value by cloning given one
value(:any)
:any
the NULL constant
return given value from current function
value(:any)
:nothing
check if given variable is defined
symbol(:string,:literal)
:logical
if condition is not false or null perform given action, otherwise perform alternative action
condition(:any)action(:block)alternative(:block)
:any
perform action, if given condition is false or null
condition(:any)action(:block,:bytecode)
:nothing
perform action, if given condition is false or null and return condition result
condition(:any)action(:block,:bytecode)
:logical
undefine given symbol, if already defined
symbol(:string,:literal)
:nothing
pop top values from stack
number(:integer)
discard(:logical): do not return anything
:any
execute action until the given condition is not false or null
action(:block,:bytecode)condition(:block,:bytecode)
:nothing
get symbol value by given name
symbol(:string,:word,:literal,:pathliteral)
:any
check conditions one by one and execute corresponding block accordingly
conditions(:block)
any(:logical): check all conditions, without breaking, regardless of successhas(:any): prepend given value to each of the conditions
:logical
check if a specific condition is fulfilled and, if so, execute given action
condition(:block)action(:block)
:logical
execute action while the given condition is is not false or null
condition(:null,:block,:bytecode)action(:block,:bytecode)
:nothing
create closure-style block by embedding given words
embed(:string,:word,:literal,:dictionary,:block)body(:block)
:block
Cryptography- or encoding-related functions
calculate the CRC32 polynomial of given string
value(:string,:literal,:pathliteral)
:string,:nothing
decode given value (default: base-64)
value(:string,:literal,:pathliteral)
url(:logical): decode URL based on RFC3986
:string,:nothing
get digest for given value (default: MD5)
value(:string,:literal,:pathliteral)
sha(:logical): use SHA1
:string,:nothing
encode given value (default: base-64)
value(:string,:literal,:pathliteral)
url(:logical): encode URL based on RFC3986spaces(:logical): also encode spacesslashes(:logical): also encode slashesfrom(:string): source character encoding (default: CP1252)to(:string): target character encoding (default: UTF-8)
:string,:nothing
get hash for given value
value(:any)
string(:logical): get as a string
:integer,:string
Functions for creating and query databases
close given database
database(:database)
:nothing
opens a new database connection and returns database
name(:string)
sqlite(:logical): support for SQLite databasesmysql(:logical): support for MySQL databases
:database
execute command or block of commands in given database and get returned rows
database(:database)commands(:string,:block)
id(:logical): return last INSERT idwith(:block): use arguments for parametrized statement
:null,:integer,:block
create or load a persistent store on disk
path(:string,:literal)
deferred(:logical): save to disk only on program terminationglobal(:logical): save as global storenative(:logical): force native/Arturo formatjson(:logical): force Json formatdb(:logical): force database/SQlite format
:range
Functions for manipulating dates
get date after given one using interval
date(:literal,:pathliteral,:date)
nanoseconds(:integer): add given number of nanosecondsmilliseconds(:integer): add given number of millisecondsseconds(:integer): add given number of secondsminutes(:integer): add given number of minuteshours(:integer): add given number of hoursdays(:integer): add given number of daysweeks(:integer): add given number of weeksmonths(:integer): add given number of monthsyears(:integer): add given number of years
:date
get date before given one using interval
date(:literal,:pathliteral,:date)
nanoseconds(:integer): subtract given number of nanosecondsmilliseconds(:integer): subtract given number of millisecondsseconds(:integer): subtract given number of secondsminutes(:integer): subtract given number of minuteshours(:integer): subtract given number of hoursdays(:integer): subtract given number of daysweeks(:integer): subtract given number of weeksmonths(:integer): subtract given number of monthsyears(:integer): subtract given number of years
:date
check if given date is a Friday
date(:date)
:logical
check if given date is in the future
date(:date)
:logical
check if given year is a leap year
year(:integer,:date)
:logical
check if given date is a Monday
date(:date)
:logical
get date/time now
:date
check if given date is in the past
date(:date)
:logical
check if given date is a Saturday
date(:date)
:logical
check if given date is a Sunday
date(:date)
:logical
check if given date is a Thursday
date(:date)
:logical
check if given date is today
date(:date)
:logical
check if given date is a Tuesday
date(:date)
:logical
check if given date is a Wednesday
date(:date)
:logical
Exceptions and error handling
an arithmetic error
an assertion error
a conversion error
an index error
a library error
a name error
a package error
a generic runtime error
a syntax error
a system error
throw an error with given message
message(:string,:errorkind)
as(:errorkind): consider the error as one of given subtype
:nothing
perform action, and return true if errors were thrown
action(:block,:bytecode)
:logical
perform action and catch possible errors
action(:block,:bytecode)
verbose(:logical): print all error messages as usual
:null,:error
a type error
a UI error
a value error
a VM error
Functions for reading, writing, and manipulating files
copy file at path to given destination
file(:string)destination(:string)
directory(:logical): path is a directory
:nothing
delete file at given path
file(:string)
directory(:logical): path is a directory
:nothing
check if given path exists and corresponds to a directory
path(:string)
:logical
check if file/directory at given path exists
path(:string)
:logical
check if given path exists and corresponds to a file
path(:string)
:logical
hidden?
check if file/folder at given path is hidden
file(:string)
:logical
move file at path to given destination
file(:string)destination(:string)
directory(:logical): path is a directory
:nothing
check permissions of given file
file(:string)
set(:dictionary): set using given file permissions
:null,:dictionary
read file from given path
file(:string)
lines(:logical): read file lines into blockjson(:logical): read Json into valuecsv(:logical): read CSV file into a block of rowsdelimiter(:char): read CSV file with a specific delimiterwithHeaders(:logical): read CSV headershtml(:logical): read HTML into node dictionaryxml(:logical): read XML into node dictionarymarkdown(:logical): read Markdown and convert to HTMLtoml(:logical): read TOML into valuebytecode(:logical): read file as Arturo bytecodebinary(:logical): read as binaryfile(:logical): read as file (throws an error if not valid)
:string,:binary,:block
rename file at path using given new path name
file(:string)name(:string)
directory(:logical): path is a directory
:nothing
create symbolic link of file to given destination
file(:string)destination(:string)
hard(:logical): create a hard link
:nothing
check if given path exists and corresponds to a symlink
path(:string)
:logical
get file timestamps
file(:string)
:null,:dictionary
unzip given archive to destination
destination(:string)original(:string)
:nothing
get file size for given path
file(:string)
:quantity
write content to file at given path
file(:null,:string)content(:any)
append(:logical): append to given filedirectory(:logical): create directory at pathjson(:logical): write value as Jsoncompact(:logical): produce compact, non-prettified Json codebinary(:logical): write as binary
:nothing
zip given files to file at destination
destination(:string)files(:block)
:nothing
Functions and utilities for using the terminal and standard input/output
clear terminal
:nothing
get colored version of given string
color(:color)string(:string)
bold(:logical): bold fontunderline(:logical): show underlinedkeep(:logical): don't reset color at string end
:string
turn cursor visibility on/off
visible(:logical)
:nothing
move cursor to given coordinates
x(:null,:integer)y(:null,:integer)
:nothing
print prompt and get user input. If the prompt is ø, get a single character
prompt(:null,:string)
repl(:logical): get input as if in a REPLhistory(:string): set path for saving historycomplete(:block): use given array for auto-completionshint(:dictionary): use given dictionary for typing hints
:char,:string
print given value to screen with newline
value(:any)
lines(:logical): print each value in block in a new line
:nothing
print given value to screen
value(:any)
:nothing
get info about terminal
:dictionary
Functional helpers for easier block iteration (loops, filtering, mapping, etc)
sort items in collection using given action, in ascending order
collection(:integer,:string,:literal,:dictionary,:object,:inline,:block,:range)params(:null,:literal,:block)condition(:block,:bytecode)
with(:literal): use given indexdescending(:logical): sort in descending order
:block,:nothing
chunk together consecutive items in collection that abide by given predicate
collection(:integer,:string,:literal,:dictionary,:object,:inline,:block,:range)params(:null,:literal,:block)condition(:block,:bytecode)
with(:literal): use given indexvalue(:logical): also include condition values
:block,:nothing
group together items in collection that abide by given predicate
collection(:integer,:string,:literal,:dictionary,:object,:inline,:block,:range)params(:null,:literal,:block)condition(:block,:bytecode)
with(:literal): use given indexvalue(:logical): also include condition values
:block,:nothing
collect items from given collection condition while is true
collection(:integer,:string,:literal,:dictionary,:object,:inline,:block,:range)params(:null,:literal,:block)condition(:block,:bytecode)
with(:literal): use given indexafter(:logical): start collecting after given condition becomes true
:block,:nothing
calculate the number of given collection's items that satisfy condition
collection(:integer,:string,:dictionary,:object,:inline,:block,:range)params(:null,:literal,:block)condition(:block,:bytecode)
with(:literal): use given index
:integer
check if every item in collection satisfies given condition
collection(:integer,:string,:dictionary,:object,:inline,:block,:range)params(:null,:literal,:block)condition(:block,:bytecode)
with(:literal): use given index
:logical
get collection's items by filtering those that do not fulfil given condition
collection(:integer,:string,:literal,:dictionary,:object,:inline,:block,:range)params(:null,:literal,:block)condition(:block,:bytecode)
with(:literal): use given indexfirst(:logical,:integer): only filter first element/slast(:logical,:integer): only filter last element/s
:block,:nothing,:any
left-fold given collection returning accumulator
collection(:integer,:string,:dictionary,:object,:inline,:block,:range)params(:null,:block)action(:block,:bytecode)
with(:literal): use given indexseed(:any): use specific seed valueright(:logical): perform right folding
:null,:block,:nothing
group items in collection by block result and return as dictionary
collection(:integer,:string,:literal,:dictionary,:object,:inline,:block,:range)params(:null,:literal,:block)condition(:block,:bytecode)
with(:literal): use given index
:dictionary,:nothing
loop through collection, using given iterator and block
collection(:integer,:string,:dictionary,:object,:inline,:block,:range)params(:null,:literal,:block)action(:block,:bytecode)
with(:literal): use given indexforever(:logical): cycle through collection infinitely
:nothing
map collection's items by applying given action
collection(:integer,:string,:literal,:dictionary,:object,:inline,:block,:range)params(:null,:literal,:block)condition(:block,:bytecode)
with(:literal): use given index
:block,:nothing
get maximum item from collection based on given predicate
collection(:integer,:string,:literal,:dictionary,:object,:inline,:block,:range)params(:null,:literal,:block)condition(:block,:bytecode)
with(:literal): use given indexvalue(:logical): also include predicate values
:block,:nothing
get minimum item from collection based on given predicate
collection(:integer,:string,:literal,:dictionary,:object,:inline,:block,:range)params(:null,:literal,:block)condition(:block,:bytecode)
with(:literal): use given indexvalue(:logical): also include predicate values
:block,:nothing
get collection's items that fulfil given condition
collection(:integer,:string,:literal,:dictionary,:object,:inline,:block,:range)params(:null,:literal,:block)condition(:block,:bytecode)
with(:literal): use given indexfirst(:logical,:integer): only return first element/slast(:logical,:integer): only return last element/sn(:integer): only return n-th element
:block,:nothing,:any
check if any of collection's items satisfy given condition
collection(:integer,:string,:dictionary,:object,:inline,:block,:range)params(:null,:literal,:block)condition(:block,:bytecode)
with(:literal): use given index
:logical
Logical operations (AND, OR, XOR, etc), helpers and constants for boolean values
check if all values in given block are true
conditions(:block)
:logical
return the logical AND for the given values
valueA(:logical,:block)valueB(:logical,:block)
:logical
check if any of the values in given block is true
conditions(:block)
:logical
the FALSE logical constant
returns true if given value is false; otherwise, it returns false
value(:any)
:logical
the MAYBE logical constant
return the logical NAND for the given values
valueA(:logical,:block)valueB(:logical,:block)
:logical
return the logical NOR for the given values
valueA(:logical,:block)valueB(:logical,:block)
:logical
return the logical complement of the given value
value(:logical,:block)
:logical
return the logical OR for the given values
valueA(:logical,:block)valueB(:logical,:block)
:logical
the TRUE logical constant
returns true if given value is true; otherwise, it returns false
value(:any)
:logical
return the logical XNOR for the given values
valueA(:logical,:block)valueB(:logical,:block)
:logical
return the logical XOR for the given values
valueA(:logical,:block)valueB(:logical,:block)
:logical
Network-related functions and helpers
open given URL with default browser
url(:string)
:nothing
download file from url to disk
url(:string)
as(:string): set target file
:nothing
send mail using given title and message to selected recipient
recipient(:string)title(:string)message(:string)
using(:dictionary): use given configuration
:nothing
perform HTTP request to url with given data and get response
url(:string)data(:null,:string,:dictionary)
get(:logical): perform a GET request (default)post(:logical): perform a POST requestpatch(:logical): perform a PATCH requestput(:logical): perform a PUT requestdelete(:logical): perform a DELETE requestjson(:logical): send data as Jsonheaders(:dictionary): send custom HTTP headersagent(:string): use given user agenttimeout(:integer): set a timeoutproxy(:string): use given proxy urlcertificate(:string): use SSL certificate at given pathraw(:logical): return raw response without processing
:null,:dictionary
start web server using given routes
routes(:block)
port(:integer): use given portverbose(:logical): print info logchrome(:logical): open in Chrome windows as an app
:nothing
Functions and helpers for more advanced math-related operations
get the absolute value for given integer
value(:integer,:floating,:complex,:rational)
:integer,:floating
calculate the inverse cosine of given angle
angle(:integer,:floating,:complex,:rational,:quantity)
:floating,:complex
calculate the inverse hyperbolic cosine of given angle
angle(:integer,:floating,:complex,:rational,:quantity)
:floating,:complex
calculate the inverse cosecant of given angle
angle(:integer,:floating,:complex,:rational,:quantity)
:floating,:complex
calculate the inverse hyperbolic cosecant of given angle
angle(:integer,:floating,:complex,:rational,:quantity)
:floating,:complex
calculate the inverse cotangent of given angle
angle(:integer,:floating,:complex,:rational,:quantity)
:floating,:complex
calculate the inverse hyperbolic cotangent of given angle
angle(:integer,:floating,:complex,:rational,:quantity)
:floating,:complex
calculate the phase angle of given number
number(:complex)
:floating
calculate the inverse secant of given angle
angle(:integer,:floating,:complex,:rational,:quantity)
:floating,:complex
calculate the inverse hyperbolic secant of given angle
angle(:integer,:floating,:complex,:rational,:quantity)
:floating,:complex
calculate the inverse sine of given angle
angle(:integer,:floating,:complex,:rational,:quantity)
:floating,:complex
calculate the inverse hyperbolic sine of given angle
angle(:integer,:floating,:complex,:rational,:quantity)
:floating,:complex
calculate the inverse tangent of given angle
angle(:integer,:floating,:complex,:rational,:quantity)
:floating,:complex
calculate the inverse tangent of y / x
y(:integer,:floating,:rational)x(:integer,:floating,:rational)
:floating,:complex
calculate the inverse hyperbolic tangent of given angle
angle(:integer,:floating,:complex,:rational,:quantity)
:floating,:complex
calculate the smallest integer not smaller than given value
value(:integer,:floating,:rational)
:integer
force value within given range
number(:integer,:floating,:rational)range(:block,:range)
:integer,:floating,:rational
calculate the complex conjugate of given number
number(:complex)
:complex
calculate the cosine of given angle
angle(:integer,:floating,:complex,:rational,:quantity)
:floating,:complex
calculate the hyperbolic cosine of given angle
angle(:integer,:floating,:complex,:rational,:quantity)
:floating,:complex
calculate the cosecant of given angle
angle(:integer,:floating,:complex,:rational,:quantity)
:floating,:complex
calculate the hyperbolic cosecant of given angle
angle(:integer,:floating,:complex,:rational,:quantity)
:floating,:complex
calculate the cotangent of given angle
angle(:integer,:floating,:complex,:rational,:quantity)
:floating,:complex
calculate the hyperbolic cotangent of given angle
angle(:integer,:floating,:complex,:rational,:quantity)
:floating,:complex
get the denominator of given number
number(:integer,:floating,:rational)
:integer
convert a number into an array of digits or an array of digits back into a number
number(:integer,:block)
base(:integer): use given based (default: 10)
:block
the constant e, Euler's number
check if given number is even
number(:integer)
:logical
calculate the exponential function for given value
value(:integer,:floating,:complex,:rational)
:floating,:complex
calculate the factorial of given value
value(:integer)
:integer
get list of factors for given integer
number(:integer)
prime(:logical): prime factorization
:block
calculate the largest integer not greater than given value
value(:integer,:floating,:rational)
:integer
calculate the gamma function for given value
value(:integer,:floating,:rational)
:floating
calculate greatest common divisor for given collection of integers
numbers(:block)
:integer
calculate the hypotenuse of a right-angle triangle with given base and height
base(:integer,:floating,:rational)height(:integer,:floating,:rational)
:floating
the IEEE floating point value of positive infinity
check whether given value is an infinite one
value(:any)
:logical
calculate least common multiplier for given collection of integers
numbers(:block)
:integer
calculate the natural logarithm of given value
value(:integer,:floating,:complex,:rational)
:floating,:complex
calculate the logarithm of value using given base
value(:integer,:floating,:rational)base(:integer,:floating,:rational)
:floating
check if given number is negative
number(:integer,:floating,:complex,:rational)
:logical
get the numerator of given number
number(:integer,:floating,:rational)
:integer
check if given number is odd
number(:integer)
:logical
the number pi, mathematical constant
check if given number is positive
number(:integer,:floating,:complex,:rational)
:logical
modular exponentation: calculate the result of (base^exponent) % divider
base(:integer)exponent(:integer)divider(:integer)
:null,:integer
check if given integer is prime
number(:integer)
:logical
calculate the product of all values in given list
collection(:block,:range)
cartesian(:logical): return the cartesian product of given sublists
:integer,:floating,:rational
get a random integer between given limits
lowerLimit(:integer,:floating,:rational)upperLimit(:integer,:floating,:rational)
:integer,:floating
calculate the reciprocal of given number
value(:integer,:floating,:rational)
:rational
round given value
value(:integer,:floating,:rational)
to(:integer): round to given decimal places
:floating
calculate the secant of given angle
angle(:integer,:floating,:complex,:rational,:quantity)
:floating,:complex
calculate the hyperbolic secant of given angle
angle(:integer,:floating,:complex,:rational,:quantity)
:floating,:complex
calculate the sine of given angle
angle(:integer,:floating,:complex,:rational,:quantity)
:floating,:complex
calculate the hyperbolic sine of given angle
angle(:integer,:floating,:complex,:rational,:quantity)
:floating,:complex
get square root of given value
value(:integer,:floating,:complex,:rational)
integer(:logical): get the integer square root
:floating
calculate the sum of all values in given list
collection(:block,:range)
:integer,:floating,:rational
calculate the tangent of given angle
angle(:integer,:floating,:complex,:rational,:quantity)
:floating,:complex
calculate the hyperbolic tangent of given angle
angle(:integer,:floating,:complex,:rational,:quantity)
:floating,:complex
the number tau, mathematical constant
Functions for path manipulation and information retrieval
check if given path is an absolute path
path(:string)
:logical
extract components from path
path(:string,:color)
directory(:logical): get path directorybasename(:logical): get path basename (filename+extension)filename(:logical): get path filenameextension(:logical): get path extensionscheme(:logical): get scheme field from URLhost(:logical): get host field from URLport(:logical): get port field from URLuser(:logical): get user field from URLpassword(:logical): get password field from URLpath(:logical): get path field from URLquery(:logical): get query field from URLanchor(:logical): get anchor field from URLred(:logical): get red component from colorgreen(:logical): get green component from colorblue(:logical): get blue component from coloralpha(:logical): get alpha component from colorhsl(:logical): get HSL representation from colorhsv(:logical): get HSV representation from colorhue(:logical): get hue component from colorsaturation(:logical): get saturation component from colorluminosity(:logical): get luminosity component from color
:string,:dictionary
get files in given path
path(:string)
recursive(:logical): perform recursive searchrelative(:logical): get relative paths
:block
get normalized version of given path
path(:string,:literal,:pathliteral)
executable(:logical): treat path as executabletilde(:logical): expand tildes in path
:string,:nothing
get relative path for given path, based on current script's location
path(:string)
:string
Functions related to Quantities, physical units and constants
the mass of an alpha particle
one ten-billionth of a meter
the mass of an atomic mass unit
the number of atoms in 12 grams of carbon-12
the radius of the first Bohr orbit of the hydrogen atom
the ratio of the universal gas constant to Avogadro's number
the radius of an electron
the conductance of a superconductor
check if given quantities/units are compatible
a(:unit,:quantity)b(:unit,:quantity)
:logical
convert quantity to given unit
value(:integer,:floating,:rational,:quantity)unit(:string,:word,:literal,:unit)
:quantity
the mass of a deuteron
the charge of an electron
the mass of an electron
the energy equivalent of the mass of an electron
the gravitational constant
the energy of the ground state of the hydrogen atom
the mass of a helion
the impedance of free space
convert quantity to given unit
unit(:string,:word,:literal,:unit)value(:integer,:floating,:rational,:quantity)
:quantity
the inverse of the conductance of a superconductor
The inverse of the flux quantum
the magnetic flux of a superconductor
the universal gas constant
the mass of a muon
the mass of a neutron
the ratio of the energy of a photon to its frequency
the length of the Planck scale
the mass of the Planck scale
the temperature of the Planck scale
the time of the Planck scale
get the described property of given quantity or unit
quantity(:unit,:quantity)
hash(:logical): get property as a hash
:integer,:literal
the mass of a proton
the energy equivalent of the mass of a proton
the ratio of the energy of a photon to its frequency
the Rydberg constant
get quantity value in the appropriate numeric type
value(:quantity)
:integer,:floating,:rational
define new user unit
name(:string,:literal)value(:unit,:quantity)
symbol(:string): define main unit symboldescribes(:string): set corresponding property for new unitproperty(:logical): define a new property
:literal
the speed of light in a vacuum
the volume of one mole of an ideal gas at standard temperature and pressure
the standard pressure
the standard temperature
the mass of a tau
the cross section of an electron
the mass of a triton
get the units of given quantity
value(:unit,:quantity)
base(:logical): get base units
:unit
the permeability of free space
the permittivity of free space
the resistance of a superconductor
Functions and helpers for retrieving runtime information about different objects, components, or types
get index of function arities
:dictionary
get given attribute, if it exists
name(:string,:literal)
:null,:any
check if given attribute exists
name(:string,:literal)
:logical
get dictionary of set attributes
:dictionary
benchmark given code
action(:block,:bytecode)
get(:logical): get benchmark time
:floating,:nothing
print info for given symbol
symbol(:string,:word,:literal,:pathliteral,:symbolliteral)
get(:logical): get information as dictionary
:dictionary,:nothing
print full dump of given value to screen
value(:any)
muted(:logical): don't use color output
:nothing
get list of methods for given object or module
object(:object,:module)
:block
get current stack
:dictionary
checks if current script runs from the command-line
:logical
get currently defined symbols
:dictionary
Common functions and operations for sets (union, intersection, difference, etc)
return the difference of given sets
setA(:literal,:pathliteral,:block)setB(:block)
symmetric(:logical): get the symmetric difference
:block,:nothing
check if given sets are disjoint (they have no common elements)
setA(:block)setB(:block)
:logical
check if given sets intersect (they have at least one common element)
setA(:block)setB(:block)
:logical
return the intersection of given sets
setA(:literal,:pathliteral,:block)setB(:block)
:block,:nothing
return the powerset of given set
set(:literal,:pathliteral,:block)
:block,:nothing
check if given set is a subset of second set
setA(:block)setB(:block)
proper(:logical): check if proper subset
:logical
check if given set is a superset of second set
setA(:block)setB(:block)
proper(:logical): check if proper superset
:logical
return the union of given sets
setA(:literal,:pathliteral,:block)setB(:block)
:block,:nothing
High-level socket interface and relevant socket communication methods
accept incoming connection and return corresponding socket
server(:socket)
:socket
create new socket connection to given server port
port(:integer)
to(:string): set socket addressudp(:logical): use UDP instead of TCP
:socket
start listening on given port and return new socket
port(:integer)
blocking(:logical): set blocking mode (default: false)udp(:logical): use UDP instead of TCP
:socket
receive line of data from selected socket
origin(:socket)
size(:integer): set maximum size of received datatimeout(:integer): set timeout (in milliseconds)
:string
send given message to selected socket
destination(:socket)message(:string)
chunk(:logical): don't send data as a line of data
:nothing
send given message to selected socket and return true if successful
destination(:socket)message(:string)
:logical
close given socket
socket(:socket)
:nothing
Functions and helpers for working with statistics and samples
get average from given collection of numbers
collection(:block,:range)
:floating
get population standard deviation of given collection of numbers
collection(:block)
sample(:logical): calculate the sample standard deviation
:floating
get population kurtosis of given collection of numbers
collection(:block)
sample(:logical): calculate the sample kurtosis
:floating
get median from given collection of numbers
collection(:block)
:null,:integer,:floating
get population skewness of given collection of numbers
collection(:block)
sample(:logical): calculate the sample skewness
:floating
get population variance of given collection of numbers
collection(:block)
sample(:logical): calculate the sample variance
:floating
Functions and helpers for manipulating and dealing with strings or character blocks
get dictionary-index charset for given locale
locale(:string,:literal)
lower(:logical): return lowercase characters (default)upper(:logical): return uppercase charactersall(:logical): also return non-dictionary characters
:null,:block
check if given character/string is in ASCII
string(:char,:string)
:logical
convert given string to capitalized
string(:char,:string,:literal,:pathliteral)
:char,:string,:nothing
escape given string
string(:string,:literal,:pathliteral)
json(:logical): for literal use in JSON stringsregex(:logical): for literal use in regular expressionshell(:logical): for use in a shell commandxml(:logical): for use in an XML document
:string,:nothing
indent each line of given text
text(:string,:literal,:pathliteral)
n(:integer): pad by given number of spaces (default: 4)with(:string): use given padding
:string,:nothing
calculate Jaro distance/similarity between given strings
stringA(:string)stringB(:string)
:floating
join collection of values into string
collection(:literal,:pathliteral,:block)
with(:char,:string): use given separatorpath(:logical): join as path components
:string,:nothing
calculate Levenshtein distance/similarity between given strings
stringA(:string)stringB(:string)
align(:logical): return aligned stringswith(:char): use given filler for alignment (default: -)
:integer,:block
convert given string to lowercase
string(:char,:string,:literal,:pathliteral)
:char,:string,:nothing
check if given string is lowercase
string(:char,:string)
:logical
get matches within string, using given regular expression
string(:string)regex(:char,:string,:regex)
once(:logical): get just the first matchcount(:logical): just get number of matchescapture(:logical): get capture groups onlynamed(:logical): get named capture groups as a dictionarybounds(:logical): get match bounds onlyin(:range): get matches within given rangefull(:logical): get results as an array of match results
:integer,:dictionary,:block
check if string matches given regular expression
string(:string)regex(:string,:regex)
in(:range): get matches within given range
:logical
check if given string is numeric
string(:char,:string)
:logical
outdent each line of given text, by using minimum shared indentation
text(:string,:literal,:pathliteral)
n(:integer): unpad by given number of spaceswith(:string): use given padding
:string,:nothing
align string by adding given padding
string(:string,:literal,:pathliteral)padding(:integer)
center(:logical): add padding to both sidesright(:logical): add right paddingwith(:char): pad with given character
:string
check if string starts with given prefix
string(:string)prefix(:string,:regex)
:logical
render template with |string| interpolation
template(:string,:literal,:pathliteral)
once(:logical): don't render recursivelytemplate(:logical): render as a template
:string,:nothing
replace every matched substring/s by given replacement string and return result
string(:string,:literal,:pathliteral)match(:string,:regex,:block)replacement(:string,:block)
:string,:nothing
strip whitespace from given string
string(:string,:literal,:pathliteral)
start(:logical): strip leading whitespaceend(:logical): strip trailing whitespace
:string,:nothing
check if string ends with given suffix
string(:string)suffix(:string,:regex)
:logical
takes a dictionary of translations and replaces each instance sequentially
string(:string,:literal,:pathliteral)translations(:dictionary)
:string,:nothing
truncate string at given length
string(:string,:literal,:pathliteral)cutoff(:integer)
with(:string): use given fillerpreserve(:logical): preserve word boundaries
:string,:nothing
convert given string to uppercase
string(:char,:string,:literal,:pathliteral)
:char,:string,:nothing
check if given string is uppercase
string(:char,:string)
:logical
check if given string consists only of whitespace
string(:string)
:logical
word wrap a given string
string(:string,:literal,:pathliteral)
at(:integer): use given max line width (default: 80)
:string
Functions and helpers for interacting with the operation system and shell
get command-line arguments as a list
:block
get all command-line arguments parsed as a dictionary
:dictionary
get local or global configuration
:store
get environment variables
:dictionary
execute given shell command
command(:string)
args(:block): use given command argumentsasync(:logical): execute asynchronously as a process and return idcode(:logical): return process exit codedirectly(:logical): execute command directly, as a shell command
:string,:dictionary
exit program
:nothing
exit program with error message
message(:string)
code(:integer): return given exit codeunstyled(:logical): don't use default error template
:logical
get path information
:dictionary
pause program's execution~for the given amount of time
time(:integer,:quantity)
:nothing
get information on current process/program
:dictionary
get embedded information about the current script
:dictionary
check if current user has administrator/root privileges
:logical
get current system information
:dictionary
kill process with given id
id(:integer)
code(:integer): use given error code
:nothing
Built-in types, custom user types/objects and related helpers
checks if given value is of type :attribute
value(:any)
:logical
checks if given value is of type :attributeLabel
value(:any)
:logical
checks if given value is of type :binary
value(:any)
:logical
checks if given value is of type :block
value(:any)
:logical
checks if given value is of type :bytecode
value(:any)
:logical
checks if given value is of type :char
value(:any)
:logical
checks if given value is of type :color
value(:any)
:logical
checks if given value is of type :complex
value(:any)
:logical
create a type constructor method automatically using given arguments
arguments(:literal,:block)
:method
checks if given value is of type :database
value(:any)
:logical
checks if given value is of type :date
value(:any)
:logical
define new type with given prototype
type(:type)prototype(:type,:dictionary,:block)
:nothing
checks if given type is defined
type(:type,:string,:word,:literal)
:logical
checks if given value is of type :dictionary
value(:any)
:logical
checks if given value is of type :error
value(:any)
:logical
checks if given value is of type :errorKind
value(:any)
:logical
checks if given value is of type :floating
value(:any)
:logical
checks if given value is of type :function
value(:any)
builtin(:logical): check if, internally, it's a built-in
:logical
checks if given value is of type :inline
value(:any)
:logical
checks if given value is of type :integer
value(:any)
big(:logical): check if, internally, it's a bignum
:logical
get derivative type with given prototype
type(:type)prototype(:dictionary,:block)
:type
check whether value is of given type
type(:type,:block)value(:any)
:logical
checks if given value is of type :label
value(:any)
:logical
checks if given value is of type :literal
value(:any)
:logical
checks if given value is of type :logical
value(:any)
:logical
checks if given value is of type :method
value(:any)
:logical
checks if given value is of type :null
value(:any)
:logical
checks if given value is a custom-type object
value(:any)
:logical
checks if given value is of type :path
value(:any)
:logical
checks if given value is of type :pathLabel
value(:any)
:logical
checks if given value is of type :pathLiteral
value(:any)
:logical
checks if given value is of type :quantity
value(:any)
big(:logical): check if, internally, it's a bignum
:logical
checks if given value is of type :range
value(:any)
:logical
checks if given value is of type :rational
value(:any)
big(:logical): check if, internally, it's a bignum
:logical
checks if given value is of type :regex
value(:any)
:logical
checks if given value is of type :socket
value(:any)
:logical
create a sort descriptor method automatically using given type field
field(:literal)
:method
checks if given value is of type :store
value(:any)
:logical
checks if given value is of type :string
value(:any)
:logical
checks if given value is of type :symbol
value(:any)
:logical
checks if given value is of type :symbolLiteral
value(:any)
:logical
convert value to given type
type(:type,:block)value(:any)
format(:string): use given format (for dates or floating-point numbers)unit(:string,:literal): use given unit (for quantities)intrepid(:logical): convert to bytecode without error-line trackinghsl(:logical): convert HSL block to colorhsv(:logical): convert HSV block to color
:any
get type of given value
value(:any)
:type
checks if given value is of type :type
value(:any)
:logical
checks if given value is of type :unit
value(:any)
:logical
checks if given value is of type :version
value(:any)
:logical
checks if given value is of type :word
value(:any)
:logical
UI- and webview-related helpers
show notification with given title and message
title(:string)message(:string)
info(:logical): show informational notificationwarning(:logical): show notification as a warningerror(:logical): show notification as an error
:nothing
set clipboard content to given text
content(:string)
:nothing
show a file selection dialog and return selection
title(:string)
folder(:logical): select folders instead of filespath(:string): use given starting path
:string
show popup dialog with given title and message and return result
title(:string)message(:string)
info(:logical): show informational popupwarning(:logical): show popup as a warningerror(:logical): show popup as an errorquestion(:logical): show popup as a questionok(:logical): show an OK dialog (default)okCancel(:logical): show an OK/Cancel dialogyesNo(:logical): show a Yes/No dialogyesNoCancel(:logical): show a Yes/No/Cancel dialogretryCancel(:logical): show a Retry/Cancel dialogretryAbortIgnore(:logical): show an Abort/Retry/Ignore dialogliteral(:logical): return the literal value of the pressed button
:logical,:literal
get clipboard content
:string
show webview window with given url or html source
content(:string,:literal)
title(:string): set window titlewidth(:integer): set window widthheight(:integer): set window heightfixed(:logical): window shouldn't be resizablemaximized(:logical): start in maximized modefullscreen(:logical): start in fullscreen modeborderless(:logical): show as borderless windowtopmost(:logical): set window as always-on-topdebug(:logical): add inspector consoleon(:dictionary): execute code on specific eventsinject(:string): inject JS code on webview initialization
:nothing