Pacioli

Java implementation of the Pacioli language

View project onGitHub

Pacioli Manual

Manual for Pacioli 0.4


Contents

Pacioli

A Paciolo program consists of definitions organized in modules.

Program

A program is a file containing a collection of definitions. A program can include other programs with an include and libraries with an import. A line comment starts with an #

# This is an example program

import si;
import geometry;

include some_dir/some_file;

define ...

A module provides namespaces for

  • values and functions
  • index sets
  • units and unit vectors
  • types

After the definitions have been processed, the toplevel expressions in a module are evaluated in the order they appear in the file.

Toplevel Definitions

Definitions

A definition starts with keyword define followed by a name, the equal sign, and an expression. A value is defined like

define x = expression;

and a function like

define f(x, y, ..., z) = expression;

Declarations

A definition can be accompanied by a type declaration. A declaration starts with keyword declare followed by a name, a pair of colons, and a type. declare x :: type;

Declarations are optional, except for recursive functions. If a type is declared then it is checked against the definition's infered type. A declaration may restrict the type, but not generalize or contradict it.

Matrix Definitions

Syntax is

defmatrix x :: type = {
    foo, bar -> 123,
    ...
};

A matrix of the declared type with the given numbers is defined.

Conversion Definitions

Syntax is same as declaration

defconv foo :: matrix type;

A conversion matrix of the declared type is defined as value. The type's row and column dimension must be the same.

Index Definitions

An index set definition starts with keyword defindex followed by a name, the equal sign, and a set of names.

defindex Foo = {foo, bar, baz};

The defined name is used in matrix types.

Unit Definitions

A unit definition starts with keyword defunit and can define a base unit, a derived unit, or a unit vector.

A base unit definition requires a name and a string to be used in output.

defunit metre "m";

A derived unit requires an additonal unit expression. This is an expression with operators *, / and ^ on base units or other derived units.

defunit knot "kn" = 0.51444444*metre/second;

A unit vector is defined for an index set by specifying a unit for each index key. An exclamation mark seperates the index set name from the unit vector name.

defunit Foo!unit = {foo: metre, bar: knot, ...};

Unit vectors are used in matrix types.

Type Definitions

Syntax is

deftype type = type;

The defined type must be a parametric type.

The Type System

A type judgement states that an expression is of some type. It is of the form

expression :: schema

Type judgements are used as input in definitions and declarations to declare a type, and as output by the compiler when the inferred types are displayed.

The type schema introduces type variables. A type schema is can introduce ordinary type varibles, index variables, or unit varibles.


for_type a,b,...: type   
for_index P,Q,...: type   
for_unit u,v,...: type

Index variables are written in uppercase by convention.

A type is one of the two special types for functions and matrices, or the generic parametric type. The function and matrix type are described in the next section. A parametric type is of the form

Foo(type, type, ...)

Built in types List, Tuple and Boole are parametric types.

Values

Pacioli supports numbers, booleans, lists, tuples, functions and incides.

Matrices

Any numerical value is a matrix. A scalar is a 1x1 matrix. A vector is a 1xN or a Nx1 matrix.

The type of a matrix is of the form dim per dim. The row and column types are expressions on units and unit vectors with operators *, /, ^ and %. The grammar of the matrix type's dimensions is

dim ::= dim * dim                          dimensional multiplication
      | dim / dim                          dimensional division
      | dim ^ integer                      dimensional power
      | dim % dim                          dimensional Kronecker
      | term                               matrix type terminal

term ::= identifier ! identifier           dimensioned vector
       | identifier !                      dimensionless vector
       | identifier                        dimensioned number
       | 1                                 dimensionless number

A terminal in a row or column type expression is the name of a scalar unit or the name of a dimensioned vector space. A unit scalar is the dimensionless 1 or a unit like a gram or a metre. A dimensioned vector space is distinguished from a scalar by an exclamation mark. The exclamation mark indicates a vector space and is always preceded by the name of the space's index set.

The matrix type is interpreted at runtime as a unit matrix. For each dimensioned vector space the representative unit vector is assumed to be available. Each entry in a matrix type is then given by

(x per y)[i,j] = x[i] / y[j]

The runtime contents of non-terminals is defined inductively, starting from the contents of the unit vector terminals. Let v and w be unit vectors


(v * w)[i] = v[i] * w[i]  
(v / w)[i] = v[i] / w[i]  
(v^n)[i] = v[i]^n  
(v % w)[i%j] = v[i] * v[j]

The pair i%j in the last rule is a compound index. Tensors are matricized with the Kronecker product. This makes multi-dimensional data transparent for matrices and addresses the issue in the indices. Multi-dimensional data is indexed with compound indices instead of multiple row or column indices. See Indices.

Indices

Matrices in Pacioli are indexed by general index sets, not necessarily integers. Indices are first class language members. They are accessible via functions row_domain and column_domain or via literal syntax x@y, with x an index set and y an index key. For example Foo@key13 or Bar@item42.

A consequence of the matricization of tensors is that a matrix can have any number of row indices and any number of column indices. A row key or column key is a combination of items from possibly multiple index sets. Compound literal indices are constructed with the % symbol. For example Foo@key13%Bar@item42. The index type lists all index sets. In this case:

Index(Foo, Bar)

Special key _ is the only element of the index of zero index sets:

_ :: Index()

It is used to index the empty row and column domains of scalars and vectors.

Booleans

A Boolean is one of the logical values true or false.

The type of a boolean is Boole().

Tuples

A tuple is a fixed set of values of various types. Functions in Pacioli expect a tuple of values as argument.

Use function tuple to create a tuple. It returns the tuple of arguments. Use destructuring in a let or comprehension or use function apply to retreive the elements of a tuple.

The type of a tuple is

Tuple(type, type, ...)

Lists

A list is a varying set of values of the same type.

The type of a list is

List(type)

Functions

Functions are first class values. Functions are globally defined in a module or anonymous lambdas.

The type of a function is

(type, type, ...) -> type

Expressions

Constants

Literal constants are numbers, or the Boolean values true or false.

Variables

A variable is an identifier built from alphanumeric characters and undercores. A variable can be local or it can refer to a defined value or function.

Unit Expressions

A matrix type surrounded by pipes is a unit expression. For example |metre| or |Foo!unit per Foo!|.

Operators

Operators grouped by precedence

-               negative
^T              transpose
^R              reciprocal
^D              dim_inv

'^'             mexpt
^               expt

per             dim_div

'.*'            scale
'*.'            rscale
'/.'            scale_down
'./'            lscale_down
*               multiply
/               divide
\               left_divide
'*'             mmult
'/'             right_division
'\'             left_division

+               sum
-               minus

<               less
<=              less_eq
>               greater
>=              greater_eq
=               equal
!=              not_equal

and             and
or              or
<=>             equal
==>             implies
<==             follows_from

Function Application

A function application is of the form

foo(expression, expression, ... )

Lambda

An anonymous function is of the form

lambda (x, y, ... ) expression end

If

An if is of the form

if expression then
  expression
else if expression then
  expression
...
else
  expression
end

Let

A let is of the form

let 
    foo = expression,
    bar = expression,
    ...
in
    expression
end

Each variable can also be a list of variables surrounded by parenthesis to destructure a tuple.

Comprehensions

A list comprehension is of the form

[ expression | clause, clause, ... ]

where each clause is

Each var can also be a list of variables surrounded by parenthesis to destructure a tuple.

Statements

A statement is of the form


begin
  statement
  statement
  ...
end

A return leaves the block prematurely.

Assignment

An assignment is of the form

var := expression;

The value stored by variable var is changed to the value of the expression. The variable can also be a list of variables surrounded by parenthesis to destructure a tuple.

Return

A return statement is of the form

return expression;

Execution of the surrounding begin end block is halted and the returned value becomes the value of the block. The expression is optional.

While

A while statement is of the form

while expression do
  statement
end

The body of the while loop is executed as long the expression is true.

If

An if statement is of the form

if expression then
  statement
else if expression then
  statement
...
else
  statement
end

The else and elseif are optional.

2013-2014 Paul Griffioen