Roll is an interactive dice language designed to help play games or to conduct experiments with probability. Roll is implemented as an interactive interpreter. Unlike most similar systems, Roll supports evaluation modes in which distributions can be computed exactly or approximated using random sampling.
The source code is available on Github.
The script roll
runs the interpreter inside rlwrap
to provide
history and line editing. An initial expression or command may optionally be provided
as a command-line argument, e.g.:
roll 3d6
roll load dnd.roll
If the command-line argument is an expression rather than a command, the interpreter merely prints the eval-mode result and immediately terminates without offering an interactive prompt.
The dice language is a functional language. Possible expressions exp include the following:
(any positive integer literal) | Examples: 3, 5, 2. |
(a literal bag of values) | Examples: {3,4,2}, {1,2,3,4,5,6}, {}, {4} |
d exp |
d is the most important expression in
Roll. d n means roll an n-sided die and return the result. For example,
d6 evaluates to any of the integers 1–6. The
expression after d need not be an integer, but it should
evaluate to an integer; for example, d(d6) is a valid
expression. To compute this expression, the interpreter will roll
a six-sided die to get a value n, then roll an n-sided die and return
the result. |
exp # exp |
# is the " repeat n
times" operator. The interpreter evaluates the first
expression to an integer n. Then it
evaluates the second expression n times and unions the results into a
single bag of integers. For example, the expression 3#d6 rolls 3 six-sided dice
and returns a bag containing the results; the expression 3#(2#d6) is equivalent
to 6#d6 . |
exp + exp |
This expression acts differently depending
on the results of the subexpressions. If both of the operands are
integers, it computes the sum of the two integers. If one operand
is an integer and the other is a bag, it adds the integer value to each
element of the bag and returns the result. It is a run-time type
error for both operands to be bags. In addition to + ,
the operators − , * , / , and % (mod)
are supported.
|
exp ++ exp |
Take the union of two subexpression results. For example,
2#d4++d6 returns the values from rolling 2 four-sided dice and one
six-sided die, in no particular order. |
compare exp relop exp |
Perform the specified comparison, returning 1 if true and 0 if false. |
sum exp |
If the subexpression is a bag, the result
is to sum the elements of the bag. If it is an integer, this
expression returns that integer. So, sum(3#d6) would
return the sum of 3 six-sided dice. |
count exp |
Similar to sum, but it returns the number of elements in the subexpression. If the subexpression is an integer, it returns 1. |
min exp in exp |
Given operands n and
b respectively, returns the least
n elements of b. b
must be a bag. An example is min 2 (3#d6) , which rolls
3 six-sided dice and returns the two least values rolled. |
max exp in exp |
Like min , but selects the largest elements.
|
let id=exp
in exp |
Binds the result of evaluating the first
subexpression to the identifier id and uses the
binding to evaluate the second subexpression. Identifiers start
with a letter and consist of letters, underscores, and primes.
For example, let x = d6 in x+x will roll a six-sided
die and double the result. Notice that the d6 in this expression
is evaluated only once. |
if exp relop exp then exp else exp |
Similar to the ML
if/then/else expression. If the condition is
true, returns the result of evaluating the first expression, otherwise
of the second expression. An example is
if d6 < 4 then d4 else d5 , which rolls a 6-sided die; if the
result is less than 4, then it rolls a 4-sided dice else rolls a 5-sided
die. The list of relational operators is mentioned below. Relational operators relop may be any of < ,
<= , = , != , >= , >
Note: since
each element of the test is parsed separately, it is not possible to
put parentheses around the comparison as in if (exp op exp) then
... . |
filter exp relop
exp |
A filter
e1
op
e2
evaluates e1
and e2
to get results v1
and v2.
Value v1 must be an integer; v2
must be a bag. Then the comparison (v1
op v) for
each element v
in bag v2
and the result is the bag with all elements v for which (v1
op
v) holds.
For example, the expression filter 4 < 5#d6
rolls 5 six-sided dice and returns any values greater than
4. If the 5#d6 evaluated to {1,2,4,6,6}, the filter
result would be {6, 6}. |
Example expressions:
d6
: Roll a 6 sided die
2 # d6
: Roll two 6 sided dice
d(d 6)
: Roll a 6 sided die to get 'n', and then role an
'n' sided die
d(sum(2#d6))
: Roll an 'n' sided die where n is the
sum of two six-sided die rolls.
if d6 < 4 then 4 else 2#d4
Roll a d6, and if that
is less than 4 return 4, otherwise return a bag consisting of the results
of rolling 2 d4's.max 2 in (3#d5)
: Return the largest 2 values after
rolling three five-sided dice. min 2 in (3#(if d6 < d6 then 1 else 2))
: Roll
two dice. If the first is smaller, return 1 else 2. Do this three times
and select the lowest two values.
(2#d6) # d6
: First argument to # must be an int.
d(2#d6)
: Argument to d
should be an int.
min 2 in 5
: Second argument to min should be a bag.
min 2 in d5
: Second argument to min should be a bag.
(2#d6) + (2#d6)
: Cannot add two bags.
let x = d6 in x + y
: Unbound identifier y.
A definition can be introduced for later use. Defined names may be multipart identifiers:
new char = 6 # sum max 3 in 4#d6
plus1 = new char + 1
Each time a definition is used, its expression is evaluated anew, unlike
identifiers introduced using let
.
Roll expressions are evaluated in the current mode. There are three different modes,
eval
, dist
, and sample
, each of which can be
entered by using them as commands:
eval
mode - evaluates the expression and returns a
single result. This is the initial mode.
dist
mode - evaluates the expression, but this time
instead of giving out a single result, returns all possible values of
the expression, with their frequency distribution.sample
mode - evaluates the expression multiple times
and returns all of the results. Run with a large enough sample size, the
frequency of certain results should approach those returned in
dist
mode.Additional commands:
mode
: view the current mode
help
: print a help message
prompt.
quit
or q
: quit
load filename
: load definitions from an external file.