Let's start with a little reminder about the syntax. The complete syntax for Untyped Plutus Core comes from the original Formal Specification of the Plutus Core Language.
Plutus Core has 7 primitive types (a.k.a. constants):
One can construct constants using the
con keyword, followed by the name of the primitive type and its value.
- Unit is denoted
- Bool are
- Bytestrings are denoted with a leading
#followed by an hexadecimal sequence;
- Strings are UTF-8 text strings, between double quotes
- Pair and lists are encapsulated between brackets
Note that each constant is named after its type. For pairs and lists -- which are compound types --, the type of their elements is specified between chevrons
A function (or simply, lambda) is constructed with the keyword
by a variable name, and a term (i.e. a constant, another function, etc..). One
can apply variables to a function using squared brackets
[ (lam x x) (con integer 42) ].
This little excerpt constructs a function that takes an argument
x and returns
it; to which we immediately apply the constant
42. If we were to evaluate this
program, it would simply output:
Plutus Core comes with a set of builtins functions which comes in handy to define certain operations. Incidentally, there's no operator even for basic arithmetic operations, everything comes as a builtin.
You'll notice also that some builtins are very domain specific and tailored to operations you'd expect a smart contract to perform on a blockchain. Hence, new builtins may be added in the future to address specific use cases that emerge.
Builtins are called with the keyword
builtin followed by their names. They may
take one, two, three or really any number of arguments. Here is the complete list of builtin functions.
Delay & Force
Plutus Core has the notion of type abstractions and type instantiations. That is, like lambdas are functions over term values, abstractions are functions over types. These abstractions allow to represent polymorphic types (such as, a list of elements, or an option type). UPLC has gotten rid of the types, but introduces two new keywords in order to preserve the abstractions in some form.
forcecan be used on a polymorphic function to instantiate one type-parameter. For example, the branches of a builtin
ifThenElsecan be of any type -- though they have to be the same for both branches. In fact,
ifThenElsehas one type parameter. To be called, it must therefore be forced once:
[ [ [ (force (builtin ifThenElse)) p ] x ] y ]
delaycan be used to defer the evaluation of a certain term; this allows to artificially construct or preserve type abstractions, but also, to introduce a certain level of laziness in parts of the program.
In addition to primitive types, Plutus Core also has a more generalized
data-type which is meant to represent any possible data-type in a program.
TODO: Give additional detail about how the serialization is done and how to construct a Data.
In particular, revisit after #34 (opens in a new tab) since the introduction of "list" and "pair" keywords may come in handy.
Finally, UPLC programs are wraps in a
program declaration, which indicates
the version (e.g.
1.0.0) of Plutus Core that this programs uses. You don't
have to worry about that too much. Aiken supports the latest Plutus version