iRODS Rule Language Cheat Sheet
- 1. IRODS Cheat Sheet (version 3+)
Version 0.9 by Samuel Lampa, BILS (bils.se)
Contact author: samuel dot lampa at bils dot se
Numeric Literals
1 # integer
1.0 # double
Strings
'A 'string', ' ++ "another ”string”"
# Some valid escape characters:
“n, r, t, , ', ", $, *"
Boolean constants
true # True
false # False
Boolean comparison
! # Not
&& # And
|| # Or
%% # Or used in the "##" syntax
Arithmetic operators
- # Negation
^ # Power
* # Multiplication
/ # Division
% # Modulors
- # Subtraction
+ # Addition
Arithmetic comparison
> # Greater than
< # Less than
>= # Greater than or equal
<= # Less than or equal
Arithmetic functions
exp(<num>)
log(<num>)
abs(<num>)
floor(<num>) # always returns integer
ceiling(<num>) # always returns integer
average(<num>, <num>, ...)
max(<num>, <num>, ...)
min(<num>, <num> , ...)
String functions
writeLine("stdout", "Hi!");
Prints out “Hi!.”
"This “++”is”++” a string."
Equals to “This is a string.”
"This is a string." like "This is*"
Equals to true
"This is." like regex "Th.*is[.]"
Equals to true
substr("This is a string.", 0, 4)
Output: This
strlen("This is a string.")
Output: 17
split("This is a string.", " ")
Equals to: [This,is,a,string.]
writeLine("stdout", triml("This is a
string.", " "));
Equals to: is a string.
trimr("This is a string.", " ")
Equals to: This is a
List functions
list(<elem>, <elem>, ...)
Creates a new list, Ex:
list("This","is","a","list")
elem(<list>, <index>)
Retrieves elements from a list (0-indexed). Ex:
elem(list("This","is","a","list"),0)
# returns “This”
setelem(<list>, <index>, <value>)
Updates an item in a list. Ex:
setelem(list("A","list"),0,"My")
# Evaluates to list("My","list").
size(<list>)
Gives the size of a list. Ex:
size(list("This","is","a","list"))
# evaluates to 4.
hd(<list>)
Gives the head of a list, Ex:
hd(list("This","is","a","list"))
# Evaluates to "This"
tl(<list>)
Gives the tail of a list. Ex:
tl(list("This","is","a","list"))
# Evaluates to list("is","a","list")
cons(<element>, <list>)
Add elements to a list. Ex:
cons("My",list("list"))
# Evaluates to list("My","list").
Tuples
Tuples are created like so:
( <component>, ..., <component> )
If statements
Logical if:
if <expr> then { <actions> }
else { <actions> }
Logical if example:
if (*A==1) then { true; } else {
false; }
Functional if (returning value of any type):
if <expr> then <expr> else <expr>
Functional if example:
if true then 1 else 0
if *A==1 then true else false
The following abbreviation are allowed (the red
striked part can be abbreviated) in functional ifs:
if (...) then { ... } else { ... }
if (...) then { ... } else { if (...)
then {...} else {...} }
Multiple abbreviations can be combined for
example:
if (*X==1) { *A = "Mon"; }
else if (*X==2) {*A = "Tue"; }
else if (*X==3) {*A = "Wed"; }
Foreach loops
Without iterator:
foreach(*C) {
writeLine("stdout", *C);
}
With the iterator variable (*E in this case):
foreach(*E in *C) {
writeLine("stdout", *E);
}
- 2. Defining functions
Functions can be thought of as microservices written
in the rule language and are defined like this:
<name>(<param>, ..., <param>) = <expr>
Example:
square(*n) = *n * *n
Variables in functions: The let expression
As function definitions are based on expressions
rather than action sequences, we cannot put an
assignment directly inside an expression. For
example, the following is not a valid function
definition:
quad(*n) = *t = *n * *n; *t * *t
To solve this problem, the let expression provides
scoped values in an expression. The general syntax for
the let expression is:
let <assignment> in <expr>
For example:
quad(*n) = let *t = *n * *n in *t * *t
The variable on the left hand side of the assignment in
the let expression is a let-bound variable. The scope of
such a variable is within the let expression. A let
bound variable should not be reassigned inside the let
expression.
Defining Rules
Define rules with nontrivial rule conditions like this:
<name>(<param>, ..., <param>) {
on(<condition>) { <actions> }
}
The rule condition can be skipped for rules with trivial
or non-existent conditions:
<name>(<param>, ..., <param>) {
<actions>
}
A rule can have multiple conditional expressions:
<name>(<param>, ..., <param>) {
on(<condition>) { <actions> } …
on(<condition>) { <actions> }
}
Generating and Capturing Errors
In a rule, we can also prevent the rule from failing
when a microservice fails:
errorcode(msi)
The errormsg microservice captures the error
message, allows further processing of the error
message, and avoids the default logging of the error
message, like so:
errormsg(msi, *msg)
In a rule, the fail() and failmsg() microservices can be
used to generate errors.
fail(errorcode) generates an error with an error code.
Example:
fail(-1)
failmsg(<errorcode>, <errormsg>) generates an
error with an error code and an error message.
Example:
failmsg(-1, "this is an error message")
The msiExit microservice is similar to failmsg:
msiExit("-1", "msi")
Inductive Data Types
The features discussed in this section are currently
under development!
An inductive data type is a data type for values that
can be defined inductively, i.e. more complex values
can be constructed from simpler values using
constructors. General syntax:
data <name> [ ( <type parameter
list> ) ] =
| : <data constructor type>
…
| <data constructor name> : <data
constructor type>
For example, a data type that represents the natural
numbers can be defined as
data nat =
| zero : nat
| succ : nat -> nat
Here the type name defined is “nat.” The type
parameter list is empty. If the type parameter list is
empty, we may omit it. There are two data
constructors. The first constructor “zero” has type
“nat,” which means that “zero” is a nullary constructor
of nat. We use “zero” to represent “0”. The second
constructor “succ” has type “nat -> nat” which means
that “succ” is unary constructor of nat. We use “succ”
to represent the successor. With these two
constructors we can represent all natural
numbers: zero, succ(zero), succ(succ(zero)).
Pattern matching
If a data type has more than one data structure, then
the "match" expression is useful:
match <expr> with
| <pattern> => <expr>
…
| <pattern> => <expr>
For example, given the nat data type we defined
earlier, we can define the following function using the
match expression:
add(*x, *y) =
match *x with
| zero => *y
| succ(*z) => succ(add(*z, *y))
For another example, given the "tree" data type we
defined earlier, we can define the following function
size(*t) =
match *t with
| empty => 0
| node(*v, *l, *r) => 1 +
size(*l) + size(*r)