chore: retire mdbook

This commit is contained in:
rvcas 2022-12-15 14:10:11 -05:00 committed by Lucas
parent cbe7ad65f7
commit 34d76bc280
20 changed files with 0 additions and 1773 deletions

View File

@ -1,47 +0,0 @@
name: mdBook
on:
workflow_dispatch:
push:
branches:
- main
pull_request:
permissions:
contents: read
pages: write
id-token: write
# Allow one concurrent deployment
concurrency:
group: "pages"
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Pages
uses: actions/configure-pages@v2
- name: Setup mdBook
uses: peaceiris/actions-mdbook@v1
with:
mdbook-version: "latest"
- run: mdbook build book -d ../_site
- name: Upload artifact
uses: actions/upload-pages-artifact@v1
deploy:
if: ${{ github.ref == 'refs/heads/main' }}
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v1

View File

@ -1,5 +1,4 @@
version="0.3.2"
[scripts]
book = "mdbook serve book -d ../_site"
publish = "cargo workspaces publish"

1
book/.gitignore vendored
View File

@ -1 +0,0 @@
book

View File

@ -1,9 +0,0 @@
[book]
authors = ["Ch1n3du"]
language = "en"
multilingual = false
src = "src"
title = "The Aiken Programming Language"
[output.html]
mathjax-support = true

View File

@ -1,17 +0,0 @@
# Summary
- [Introduction](./introduction.md)
- [Getting Started](./getting-started.md)
- [Language Tour](./language-tour.md)
- [Primitive Types](./language-tour/primitive-types.md)
- [Variables & Constants](./language-tour/variables-and-constants.md)
- [Functions](./language-tour/functions.md)
- [Custom Types](./language-tour/custom-types.md)
- [Control flow](./language-tour/control-flow.md)
- [Modules](./language-tour/modules.md)
- [Untyped Plutus Core](./uplc.md)
- [Syntax](./uplc/syntax.md)
- [Command-line utilities](./uplc/cli.md)
- [Builtins](./uplc/builtins.md)
- [Ecosystem Overview](./ecosystem-overview.md)
- [Resources](./resources.md)

View File

@ -1,161 +0,0 @@
# Ecosystem Overview
Within the Cardano community there has been a flourishing ecosystem
of alternative languages for writing smart contracts. So naturally, one might ask about
the differences between these and which they should use for their use case. There is
also a big misconception about how writing smart contracts actually works on Cardano. In this document,
we'll list some of the main alternatives along with their differences and similarities. Before we get into this though, let's discuss the misconception first so everyone is on the same page.
## The Misconception
**Cardano uses Haskell for smart contracts**
This is **not** entirely true.
The main Cardano node implementation does indeed happen to be written in
Haskell. The virtual machine for executing smart contracts that comes baked
into the node is then of course also implemented in Haskell. **But** that does
not mean that it is Haskell itself which is executed by the smart contract
virtual machine. Aiken actually has a fully working version of this [virtual
machine](https://github.com/txpipe/aiken/blob/main/crates/uplc/src/machine.rs#L63)
written in Rust.
So what's going on here? What is actually being executed?
Well, there is something called [Untyped Plutus Core](./uplc.md) which is the
lowest level representation of a smart contract and it is this low level
representation that actually gets executed by the virtual machine. So contrary
to popular knowledge, there isn't actually a coupling to Haskell. Armed with
this knowledge one may now ask another question:
**So what am I writing when I write Plutus?**
In the wild, Plutus tends to refer to one of three things:
1. _Plutus Core_, the low-level interpreted code that is executed by the
Cardano virtual machine.
2. _PlutusTx_, a Haskell framework that compiles to Plutus Core through the
means of a GHC plugin.
3. The _Plutus Platform_, which more broadly includes _Plutus Core_, _PlutusTx_
and most of the tools developed around _Plutus Core_.
Most of the time, when people say _Plutus_, they mean _PlutusTx_, which has led
to a popular belief that Plutus is in fact Haskell.
_PlutusTx_ being built as a GHC plugin means that you even use Haskell tooling
like cabal for it. Even so, you are technically not writing Haskell. Code that
one writes using _PlutusTx_ is consumed by the plugin and then transformed into
_Untyped Plutus Core_. Essentially, it takes the intermediate representation of
Haskell, GHC Core, and turns that into Untyped Plutus Core. This results in not
needing to write a new parser and type checker. What you end up with is a kind
of embedded language that looks and feels like Haskell but the target runtime
is not GHC.
## The Alternatives
Now that this misconception is out of the way it should be possible to see how
other new languages can be created that ultimately compile to Untyped Plutus
Core. The current alternatives range from full blown new languages to embedded
Domain Specific Languages (abbrev. eDSLs.) Here is a list of the main ones:
- [Aiken](https://github.com/txpipe/aiken)
- [Helios](https://github.com/Hyperion-BT/Helios)
- [Plutarch](https://github.com/Plutonomicon/plutarch-plutus)
- [plu-ts](https://github.com/HarmonicLabs/plu-ts)
- [Scalus](https://github.com/nau/scalus)
The creators of each of these projects all know each other and are in open
communication with each other.
### Aiken
Aiken is a brand new language with it's own syntax and compiler. It is not Rust. The compiler
happens to be written in Rust but it is not Rust. Not only is Aiken a compiler
for a new language but we've also developed everything in such a way that all
the libraries we created in Rust are re-usable by people interested in doing
more low-level things. One example of this is
[Lucid](https://github.com/spacebudz/lucid), which uses Aiken's
[uplc](https://crates.io/crates/uplc) crate to evaluate transactions before
submission to calculate exact redeemer ExUnits without using a node, ogmios, or
blockfrost.
As a language, Aiken is purely functional with static typing and type
inference. This means most of the time the compiler is smart enough to know
what the type of something is without you annotating it. It also let's you make
custom types that are similar to records and enums. It does not have
higher-kinded types or typeclasses because Aiken aims for simplicity. Writing
smart contracts can be tedious, and we therefore believe that a language
should remain simple to avoid silly mistakes.
On-chain scripts are typically small in size and scope (relatively, compared to
other kind of applications being written nowadays) and, therefore, do not
require as much features as general-purpose languages that have to solve much
harder problems.
That being said Aiken may introduce more elaborate language features (such as
type classes/traits) at a later time if it's found that they are extremely
useful to developers.
### Helios
Helios is also a brand new language. One notable implementation difference is
that it's compiler is written in a [single javascript file without
dependencies](https://github.com/Hyperion-BT/Helios/blob/main/helios.js).
According to the creator, the intention of that was to make the compiler
implementation easier to audit.
As a language, Helios is also purely functional but has limited have type
inference. It also supports custom types similar to records and enums.
Another interesting thing is that because the compiler is a single javascript
file it's pretty easy to use Helios from within a javascript project.
### Plutarch
Plutarch is **not** a new language. You can consider it an eDSL for creating
smart contracts with Haskell. In some ways, Plutarch is what PlutusTx should
have been. There is no template Haskell involved.
Since Plutarch is just Haskell, you have everything available to you. Type
inference, typeclasses, higher-kinded types, etc.
### plu-ts
plu-ts is **not** a new language. You can consider it an eDSL for creating smart contracts with Typescript.
Because of this it's a bit closer to Plutarch conceptually than Aiken or Helios.
It implements it's own type system and at compile time (js runtime) checks the types to be correct.
### Scalus
A Scala implementation of Plutus.
Scalus is a set of libraries to work with Cardano Untyped Plutus Core that works on both JVM and JavaScript. This includes:
- Untyped Plutus Core (UPLC) data types and functions
- Flat, CBOR, JSON serialization
- CEK UPLC evaluation machine including execution cost calculation
- UPLC parser and pretty printer
- Type safe UPLC expression builder, think of Plutarch
- Macros to generate UPLC code from Scala code, think of PlutusTx but simpler
## Which should you use?
Only you can decide for yourself which of these fits your needs the best. Each
has made some different decisions around design and implementation. Aiken and
Helios are on the **new language** end of the spectrum while Plutarch and
plu-ts are on the eDSL end. Plutarch has the most expressive type system while
Aiken's types are in between Plutarch and Helios.
Embedded DSLs are nice because they integrate seamlessly with off-chain code and
usually allow to reuse existing tools that already work on the host language.
New languages are nice because they include bespoke checks and functionality
specifically for Cardano smart contracts directly in their compilers. While
they demand a lot of the tooling to be created anew, they also give the
opportunity to address shortcomings of existing tooling in various languages.
Which best serves your use case is for you to say. Being the maintainers behind
Aiken, we can't be fully partial in providing an unbiaised answer. We encourage
you to review the documentation, design decisions and overall project to make
an informed decision.

View File

@ -1,28 +0,0 @@
# Getting Started
## Installation
### From Source
```console
cargo install aiken
```
> **Note**
>
> _`cargo` is a package manager for Rust. To install it, please refer to [the Rust book](https://doc.rust-lang.org/stable/book/ch01-01-installation.html)._
## QuickStart
```
aiken --help
```
## Editor Integrations
The following plugins provide syntax highlighting and indentation rules for Aiken.
| Editor | Plugin |
| ---------- | --------------------------------------------------------------------------- |
| VSCode | [aiken-lang/editor-integration-vscode](https://github.com/aiken-lang/editor-integration-vscode) |
| Vim/Neovim | [aiken-lang/editor-integration-nvim](https://github.com/aiken-lang/editor-integration-nvim) |

View File

@ -1,46 +0,0 @@
# Introduction
Aiken is a new programming language and toolchain for developing
smart contracts on the [Cardano](https://cardano.org) blockchain.
## Philosophy
Our main goal is to improve the smart contract development experience for the Cardano blockchain. Aiken takes inspiration from many modern languages such as aiken, rust, and elm which are known for friendly error messages and an overall excellent developer experience. We believe Cardano deserves a dedicated language with these kinds of features, developed in the open with the community.
## Goals
- We want an easy and safe way to write Cardano smart contracts. We should be able to get started in minutes not days.
- We want a complete and delightful experience. A modern blockchain deserves a modern smart contract toolkit. This includes editor integrations such as LSP and tree-sitter along with fancy error messages.
- We want there to be as little configuration as possible. It should work out of the box and have opinionated reasonable conventions established with the community.
- We want to have a modular design so that components can be picked and chosen as needed. Like the unix philosophy.
## Roadmap
In general, the goal is to port everything we need for plutus to
Rust. This will be needed if we ever want to build a full node in
Rust. Since we will have these tools natively in Rust, we plan on
building a new high level language for writing smart contracts on Cardano.
- [x] bare minimum toolkit for working with untyped plutus core
- [x] serialize plutus core into it's on chain encoding
- [x] deserialize the on chain encoding into plutus core
- [x] Plutus Core interpreter
- [ ] [v0.1.0 - Initial Alpha](https://github.com/txpipe/aiken/milestone/1)
- [x] define aiken as a language
- [x] implement lexing/parsing with pretty error messages
- [x] type checking and inference
- [ ] uplc code gen
- [ ] [v0.2.0 - Implement standard library
](https://github.com/txpipe/aiken/milestone/2)
- [ ] [v0.3.0 - Testing Framework](https://github.com/txpipe/aiken/milestone/4)
- [ ] [v0.4.0 - Improved Tooling](https://github.com/txpipe/aiken/milestone/3)
- [ ] LSP 🚀
- [ ] syntax highlighting plugins for editors 🎨
## Components
The Aiken project is made up of a few different components. The two most important
ones are the high level Aiken language for writing smart contracts and a rust library
for working with Untyped Plutus Core.
Learn more about them in the next sections of this book.

View File

@ -1,7 +0,0 @@
# Language Tour
In this section we explore the fundamentals of the
Aiken language. We'll go over syntax, types, control flow,
and more. If you have prior programming experience this should
be enough to get you started with Aiken. We also at times touch on
how things behave and are represented at runtime.

View File

@ -1,213 +0,0 @@
# Control flow
## Blocks
Every block in Aiken is an expression. All expressions in the block are
executed, and the result of the last expression is returned.
```aiken
let value: Bool = {
"Hello"
42 + 12
False
} // False
```
Expression blocks can be used instead of parenthesis to change the precedence of operations.
```aiken
let celsius = { fahrenheit - 32 } * 5 / 9
```
## Matching
The `when *expr* is` expression is the most common kind of flow control in Aiken code. It
allows us to say "if the data has this shape then do that", which we call
_pattern matching_.
Here we match on an `Int` and return a specific string for the values 0, 1,
and 2. The final pattern `n` matches any other value that did not match any of
the previous patterns.
```aiken
when some_number is {
0 -> "Zero"
1 -> "One"
2 -> "Two"
n -> "Some other number" // This matches anything
}
```
Aiken's `when *expr* is` is an expression, meaning it returns a value and can be used
anywhere we would use a value. For example, we can name the value of a when
expression with a `let` binding.
```aiken
type Answer {
Yes
No
}
let answer = Yes
let description =
when answer is {
Yes -> "It's yes!"
No -> "It's not yes."
}
description // => "It's true!"
```
## If-Else
Pattern matching on a `Bool` value is discouraged and `if / else`
expressions should be use instead.
```aiken
let some_bool = True
if some_bool {
"It's true!"
else {
"It's not true."
}
```
Note that, while it may look like an imperative instruction: if this then do
that or else do that, it is in fact one single expression. This means, in
particular, that the return types of both branches have to match.
## Destructuring
A `when *expr* is` expression can be used to destructure values that
contain other values, such as tuples and lists.
```aiken
when xs is {
[] -> "This list is empty"
[a] -> "This list has 1 element"
[a, b] -> "This list has 2 elements"
_other -> "This list has more than 2 elements"
}
```
It's not just the top level data structure that can be pattern matched,
contained values can also be matched. This gives `when` the ability to
concisely express flow control that might be verbose without pattern matching.
```aiken
when xs is {
[[]] -> "The only element is an empty list"
[[], ..] -> "The 1st element is an empty list"
[[4], ..] -> "The 1st element is a list of the number 4"
other -> "Something else"
}
```
Pattern matching also works in `let` bindings, though patterns that do not
match all instances of that type may result in a runtime error.
```aiken
let [a] = [1] // a is 1
let [b] = [1, 2] // Runtime error! The pattern has 1 element but the value has 2
```
## Assigning names to sub-patterns
Sometimes when pattern matching we want to assign a name to a value while
specifying its shape at the same time. We can do this using the `as` keyword.
```aiken
when xs is {
[[_, ..] as inner_list] -> inner_list
_other -> []
}
```
## Checking equality and ordering in patterns
The `if` keyword can be used to add a guard expression to a when clause. Both
the patterns have to match and the guard has to evaluate to `True` for the
clause to match. The guard expression can check for equality or ordering for
`Int`.
```aiken
when xs is {
[a, b, c] if a == b && b != c -> "ok"
_other -> "ko"
}
```
## Alternative clause patterns
Alternative patterns can be given for a when clause using the `|` operator. If
any of the patterns match then the clause matches.
Here the first clause will match if the variable `number` holds 2, 4, 6 or 8.
```aiken
when number is {
2 | 4 | 6 | 8 -> "This is an even number"
1 | 3 | 5 | 7 -> "This is an odd number"
_ -> "I'm not sure"
}
```
If the patterns declare variables then the same variables must be declared in
all patterns, and the variables must have the same type in all the patterns.
```aiken
when list is {
[1, x] | x -> x // Error! Int != List(Int)
_ -> 0
}
```
## Todo
Aiken's `todo` keyword is used to indicate that some code is not yet finished.
It can be useful when designing a module, type checking functions and types but
leaving the implementation of the functions until later.
```aiken
fn not_sure_yet() -> Int {
// The type annotations says this returns an Int, but we don't need
// to implement it yet.
todo
}
fn idk() {
favourite_number() * 2
}
```
When this code is built Aiken will type check and compile the code to ensure it
is valid, and the `todo` will be replaced with code that crashes the program if
that function is run.
A message can be given as a form of documentation. The message will be traced
when the `todo` code is run.
```aiken
fn not_sure_yet() -> Int {
todo("Believe in the you that believes in yourself!")
}
```
When the compiler finds a `todo` it will print a warning, which can be useful
to avoid accidentally forgetting to remove a `todo`.
The warning also includes the expected type of the expression that needs to
replace the `todo`. This can be a useful way of asking the compiler what type
is needed if you are ever unsure.
```aiken
fn foo() {
my_complicated_function(
// What type does this function take again...?
todo
)
}
```

View File

@ -1,270 +0,0 @@
# Custom types
Aiken's custom types are named collections of keys and/or values. They are
similar to objects in object oriented languages, though they don't have
methods.
Custom types are defined with the `type` keyword.
```aiken
type Datum {
Datum { signer: ByteArray, count: Int }
}
```
Here we have defined a custom type called `Datum`. Its constructor is called
`Datum` and it has two fields: A `signer` field which is a `ByteArray`, and a
`count` field which is an `Int`.
Once defined the custom type can be used in functions:
```aiken
fn datums() {
// Fields can be given in any order
let datum1 = Datum { signer: #[0xAA, 0xBB], count: 2001 }
let datum2 = Datum { count: 1805, name: #[0xAA, 0xCC] }
[cat1, cat2]
}
```
## Multiple constructors
Custom types in Aiken can be defined with multiple constructors, making them a
way of modeling data that can be one of a few different variants.
We've already seen a custom type with multiple constructors in the Language
Tour - [`Bool`](./primitive-types.md#bool).
Aiken's built-in `Bool` type is defined like this:
```aiken
/// A Bool is a value that is either `True` or `False`
type Bool {
True
False
}
```
It's a simple custom type with constructors that takes no arguments at all!
Use it to answer yes/no questions and to indicate whether something is `True`
or `False`.
The records created by different constructors for a custom type can contain
different values. For example a `User` custom type could have a `LoggedIn`
constructor that creates records with a name, and a `Guest` constructor which
creates records without any contained values.
```aiken
type User {
LoggedIn { count: Int } // A logged in user
Guest // A guest user with no details
}
```
```aiken
let user1 = LoggedIn { count: 4 }
let user2 = LoggedIn { count: 2 }
let visitor = Guest
```
### Option
We define `Option` as a generic type like so:
```
type Option<a> {
None
Some(a)
}
```
Then, functions which fail may safely return an optional value.
```
fn get_head(a: List<a>) -> Option<a {
when a is {
[a, .._] -> Some(a)
[] -> None
}
}
```
The `Option` type is readily available in Aiken; it is part of the default types and values available by default. Don't hesitate to use it!
## Destructuring
When given a custom type record we can pattern match on it to determine which
record constructor matches, and to assign names to any contained values.
```aiken
fn get_name(user) {
when user is {
LoggedIn { count } -> count
Guest -> "Guest user"
}
}
```
Custom types can also be destructured with a `let` binding.
```aiken
type Score {
Points(Int)
}
let score = Points(50)
let Points(p) = score // This brings a let-binding `p` in scope.
p // 50
```
During destructuring you may also use discards (`_`) or spreads (`..`).
```aiken
type Dog {
Dog { name: ByteArray, cuteness: Int, age: Int }
}
let dog = Dog { name: #[67, 97, 115, 104, 101, 119], cuteness: 9001, age: 3 }
```
You will need to specify all args for a pattern match, or alternatively use the
spread operator.
```aiken
// All fields present
let Dog { name: name, cuteness: _, age: _ } = dog
builtin.decode_utf8(name) // "Cashew"
// Other fields ignored by spreading.
// Field punning is supported. Hence `age` is a shorthand for `age: age`.
let Dog { age, .. } = dog
age // 3
```
## Named accessors
If a custom type has only one variant and named fields they can be accessed
using `.field_name`.
For example using the `Dog` type defined earlier.
```aiken
let dog = Dog { name: #[82, 105, 110], cuteness: 2001 }
dog.cuteness // This returns 2001
```
This is actually so common that Aiken has some syntactic sugar for defining these
kinds of single-constructor types: one can omit the constructor:
```aiken
type Dog {
name: ByteArray,
cuteness: Int,
age: Int,
}
```
## Generics
Custom types can be be parameterised with other types, making their contents
variable.
For example, this `Box` type is a simple record that holds a single value.
```aiken
type Box<inner_type> {
Box(inner: inner_type)
}
```
The type of the field `inner` is `inner_type`, which is a parameter of the `Box`
type. If it holds an int the box's type is `Box<Int>`, if it holds a string the
box's type is `Box<String>`.
```aiken
fn foo() {
let a = Box(420) // type is Box<Int>
let b = Box("That's my ninja way!") // type is Box<String>
}
```
## Record updates
Aiken provides a dedicated syntax for updating some of the fields of a custom
type record.
```aiken
type Person {
name: ByteArray,
shoe_size: Int,
age: Int,
is_happy: Bool,
}
fn have_birthday(person) {
// It's this person's birthday, so increment their age and
// make them happy
Person { ..person, age: person.age + 1, is_happy: True }
}
```
The update syntax created a new record with the values of the initial record.
It replaces the given binding with their new values.
## Type aliases
A type alias lets you create a name which is identical to
another type, without any additional information.
```aiken
type MyNumber = Integer
```
They are most useful for simplifying type signatures.
```aiken
type Person = (String, Integer)
fn create_person(name: String, age: Integer) -> Person {
#(name, age)
}
```
## Data
At runtime custom types become an opaque Plutus' Data. In Aiken's type system
`Data` matches with any user-defined type (but with none of the primitive
types).
Thus, it's also possible to cast any `Data` to a [custom
type](./custom-types.md), and vice versa.
```aiken
fn to_datum(datum: Data) -> Datum {
let d: Datum = datum
d
}
```
Note that this conversion will fail if the given `Data` isn't actually a valid
representation of the target type. The primary use-case here is for
instantiating script contexts, datums and redeemers provided to scripts in an
opaque fashion.
It's also useful for interacting with builtins that operate on raw `Data`. In
this case, the conversation happens implicitly. Simply expect any function that
accept `Data` to automatically work on any custom type.
```aiken
type Datum {
count: Int,
}
let datum = Datum { count: 1 }
// fn(Data) -> ByteArray
builtin.serialize_data(datum) // some bytearray
```

View File

@ -1,230 +0,0 @@
# Functions
## Named functions
Named functions in Aiken are defined using the `fn` keyword. Functions can have (typed) arguments, and always have a return type. Because in Aiken, pretty much everything is an expression, functions do not have an explicit _return_ keyword. Instead, they implicitly return whatever they evaluate to.
```aiken
fn add(x: Int, y: Int) -> Int {
x + y
}
fn multiply(x: Int, y: Int) -> Int {
x * y
}
```
Functions are first class values and so can be assigned to variables, passed to
other functions, or anything else you might do with any other data type.
```aiken
/// This function takes a function as an argument
fn twice(f: fn(t) -> t, x: t) -> t {
f(f(x))
}
fn add_one(x: Int) -> Int {
x + 1
}
fn add_two(x: Int) -> Int {
twice(add_one, x)
}
```
## Pipe Operator
Aiken provides syntax for passing the result of one function to the arguments of another function, the pipe operator (`|>`). This is similar in functionality to the same operator in Elixir or F#.
The pipe operator allows you to chain function calls without using a lot of parenthesis and nesting.
For a simple example, consider the following implementation of an imaginary `string.reverse` in Aiken:
```aiken
string_builder.to_string(string_builder.reverse(string_builder.from_string(string)))
```
This can be expressed more naturally using the pipe operator, eliminating the need to track parenthesis closure.
```aiken
string
|> string_builder.from_string
|> string_builder.reverse
|> string_builder.to_string
```
Each line of this expression applies the function to the result of the previous line. This works easily because each of these functions takes only one argument. Syntax is available to substitute specific arguments of functions that take more than one argument; for more, look below in the section "Function capturing".
## Type annotations
Function arguments are normally annotated with their type, and the
compiler will check these annotations and ensure they are correct.
```aiken
fn identity(x: some_type) -> some_type {
x
}
fn inferred_identity(x) {
x
}
```
The Aiken compiler can infer all the types of Aiken code without annotations
and both annotated and unannotated code is equally safe. It's considered a
best practice to always write type annotations for your functions as they
provide useful documentation, and they encourage thinking about types as code
is being written.
## Generic functions
At times you may wish to write functions that are generic over multiple types.
For example, consider a function that consumes any value and returns a list
containing two of the value that was passed in. This can be expressed in Aiken
like this:
```aiken
fn list_of_two(my_value: a) -> List<a> {
[my_value, my_value]
}
```
Here the type variable `a` is used to represent any possible type.
You can use any number of different type variables in the same function. This
function declares type variables `a` and `b`.
```aiken
fn multi_result(x: a, y: b, condition: Bool) -> Result<a, b> {
when condition is {
True -> Ok(x)
False -> Error(y)
}
}
```
Type variables can be named anything, but the names must be lowercase and may
contain underscores. Like other type annotations, they are completely optional,
but may aid in understanding the code.
## Labeled arguments
When functions take several arguments it can be difficult for the user to
remember what the arguments are, and what order they are expected in.
To help with this Aiken supports _labeled arguments_, where function
arguments are given an external label in addition to their internal name.
Take this function that replaces sections of a string:
```aiken
fn replace(string: String, pattern: String, replacement: String) {
// ...
}
```
It can be given labels like so.
```aiken
fn replace(
in string: String,
each pattern: String,
with replacement: String,
) {
// The variables `string`, `pattern`, and `replacement` are in scope here
}
```
These labels can then be used when calling the function.
```aiken
replace(in: "A,B,C", each: ",", with: " ")
// Labeled arguments can be given in any order
replace(each: ",", with: " ", in: "A,B,C")
// Arguments can still be given in a positional fashion
replace("A,B,C", ",", " ")
```
The use of argument labels can allow a function to be called in an expressive,
sentence-like manner, while still providing a function body that is readable
and clear in intent.
## Anonymous functions
Anonymous functions can be defined with a similar syntax.
```aiken
fn run() {
let add = fn(x, y) { x + y }
add(1, 2)
}
```
## Function capturing
There is a shorthand syntax for creating anonymous functions that take one
argument and call another function. The `_` is used to indicate where the
argument should be passed.
```aiken
fn add(x, y) {
x + y
}
fn run() {
let add_one = add(1, _)
add_one(2)
}
```
The function capture syntax is often used with the pipe operator to create
a series of transformations on some data.
```aiken
fn add(x: Int , y: Int ) -> Int {
x + y
}
fn run() {
// This is the same as add(add(add(1, 3), 6), 9)
1
|> add(_, 3)
|> add(_, 6)
|> add(_, 9)
}
```
In fact, this usage is so common that there is a special shorthand for it.
```aiken
fn run() {
// This is the same as the example above
1
|> add(3)
|> add(6)
|> add(9)
}
```
The pipe operator will first check to see if the left hand value could be used
as the first argument to the call, e.g. `a |> b(1, 2)` would become `b(a, 1, 2)`.
If not it falls back to calling the result of the right hand side as a function
, e.g. `b(1, 2)(a)`.
## Documentation
You may add user facing documentation in front of function definitions with a
documentation comment `///` per line. Markdown is supported and this text
will be included with the module's entry in generated HTML documentation.
```aiken
/// Always true.
///
fn always_true(_a) -> Bool {
True
}
```

View File

@ -1,194 +0,0 @@
# Modules
Aiken programs are made up of bundles of functions and types called modules.
Each module has its own namespace and can export types and values to be used
by other modules in the program.
```aiken
// inside module lib/straw_hats/sunny.ak
fn count_down() {
"3... 2... 1..."
}
fn blast_off() {
"BOOM!"
}
pub fn set_sail() {
[
count_down(),
blast_off(),
]
}
```
Here we can see a module named `straw_hats/sunny`, the name determined by the
filename `lib/straw_hats/sunny.ak`. Typically all the modules for one
project would live within a directory with the name of the project, such as
`straw_hats` in this example.
The `pub` keyword makes this type usable from other modules.
For the functions `count_down` and `blast_off` we have omitted the `pub`
keyword, so these functions are _private_ module functions. They can only be
called by other functions within the same module.
Functions, type-aliases and constants can all be exported from a module using
the `pub` keyword.
## Import
To use functions or types from another module we need to import them using the
`use` keyword.
```aiken
// inside module src/straw_hats/laugh_tale.ak
use straw_hats/sunny
pub fn find_the_one_piece() {
sunny.set_sail()
}
```
The definition `use straw_hats/sunny` creates a new variable with the name
`sunny` and the value of the `sunny` module.
In the `find_the_one_piece` function we call the imported module's public `set_sail`
function using the `.` operator. If we had attempted to call `count_down` it
would result in a compile time error as this function is private to the
`sunny` module.
## Named import
It is also possible to give a module a custom name
when importing it using the `as` keyword.
```aiken
use unix/dog
use animal/dog as kitty
```
This may be useful to differentiate between multiple modules that would have
the same default name when imported.
## Unqualified import
Values and types can also be imported in an unqualified fashion.
```aken
use animal/dog.{Dog, stroke}
pub fn foo() {
let puppy = Dog { name: "Zeus" }
stroke(puppy)
}
```
This may be useful for values that are used frequently in a module, but
generally qualified imports are preferred as it makes it clearer where the
value is defined.
## Opaque types
At times it may be useful to create a type and make the constructors and
fields private so that users of this type can only use the type through
publically exported functions.
For example we can create a `Counter` type which holds an int which can be
incremented. We don't want the user to alter the int value other than by
incrementing it, so we can make the type opaque to prevent them from being
able to do this.
```aiken
// The type is defined with the opaque keyword
pub opaque type Counter {
Counter(value: Int)
}
pub fn new() {
Counter(0)
}
pub fn increment(counter: Counter) {
Counter(counter.value + 1)
}
```
Because the `Counter` type has been marked as `opaque` it is not possible for
code in other modules to construct or pattern match on counter values or
access the `value` field. Instead other modules have to manipulate the opaque
type using the exported functions from the module, in this case `new` and
`increment`.
## The prelude module
There are two modules that are built into the language, the first is the
`aiken` prelude module. By default its types and values are automatically
imported into every module you write, but you can still chose to import it the
regular way. This may be useful if you have created a type or value with the
same name as an item from the prelude.
```aiken
use aiken
/// This definition locally overrides the `Option` type
/// and the `Some` constructor.
pub type Option {
Some
}
/// The original `Option` and `Some` can still be used
pub fn go() -> aiken.Option<Int> {
aiken.Some(1)
}
```
The prelude module contains these types:
- `ByteArray`
- `Bool`
- `Int`
- `List<element>`
- `Nil`
- `Option<value>`
- `String`
- `Data`
And these values:
- `None`
- `Some`
- `False`
- `True`
- `Nil`
## The builtin module
The second module that comes with the language is for exposing useful builtin
functions from Plutus core. Most underlying platform functions are available
here using a snake case name. Much of Aiken's syntax ends up compiling to
combinations of certain bultins but many aren't "exposed" through the syntax
and need to be used directly. The standard library wraps these in a more
Aiken-friendly interface so you'll probably never need to use these directly
unless you're making your own standard library.
```aiken
use aiken/builtin
fn eq(a, b) {
builtin.equals_integer(a, b)
}
// is implicitly used when doing:
a == b
```
## Documentation
You may add user facing documentation at the head of modules with a module
documentation comment `////` (quadruple slash!) per line. Markdown is supported
and this text block will be included with the module's entry in generated HTML
documentation.

View File

@ -1,175 +0,0 @@
# Primitive Types
Aiken has 5 primitive types that are built in the language and can be typed as literals: booleans, integers, strings, byte arrays and data. The language also includes 2 base building blocks for associating types together: lists and tuples.
Worry not, we'll see later in this manual how to create your own custom types.
> **Note**
>
> Inline comments are denoted via `//`. We'll use them to illustrate the value
> of some expressions in examples given all across this guide.
## Bool
A `Bool` is a boolean value that can be either `True` or `False`.
Aiken defines a handful of operators that work with booleans. No doubts that they'll look
quite familiar.
| Operator | Description |
| --- | --- |
| `&&` | Logical conjunction (a.k.a 'AND') |
| <code>\|\|</code> | Logical disjunction (a.k.a. 'OR') |
| `==` | Equality |
| `!` | Logical negatation (a.k.a 'NOT') |
## Int
Aiken's only number type is an arbitrary sized integer. This means there is no underflow or overflow.
```aiken
42
14
1337
```
Literals can also be written with `_` as separators to enhance readability:
```
1_000_000
```
Aiken also supports writing integer literals in other bases than decimals. Binary, octal, and hexadecimal integers begin with `0b`, `0o`, and `0x` respectively.
```aiken
0b00001111 == 15
0o17 == 15
0xF == 15
```
Aiken has several binary arithmetic operators that work with integers.
| Operator | Description |
| --- | --- |
| `+` | Arithmetic sum |
| `-` | Arithmetic difference |
| `/` | Whole division |
| `*` | Arithmetic multiplication |
| `%` | Remainder by whole division |
Integers are also of course comparable, so they work with a variety of binary logical operators too:
| Operator | Description |
| --- | --- |
| `==` | Equality |
| `>` | Greater than |
| `<` | Smaller than |
| `>=` | Greater or equal |
| `<=` | Smaller or equal |
## String
In Aiken Strings can be written as text surrounded by double quotes.
```aiken
"Hello, Aiken!"
```
They can span multiple lines.
```aiken
"Hello
Aiken!"
```
Under the hood text strings are [UTF-8](https://en.wikipedia.org/wiki/UTF-8) encoded binaries
and can contain any valid unicode.
```aiken
"🌘 アルバイト Aiken 🌒"
```
## ByteArray
A _ByteArray_ is exactly what it seems, an array of bytes.
Aiken supports byte arrays literals, written as lists of integers ranging from 0 to 255 (a.k.a _bytes_):
```aiken
#[10, 255]
#[1, 256] // results in a parse error because 256 is bigger than 1 byte
```
It's important to mention that variables and patterns are not supported in
byte array literals due to how Untyped Plutus Core works behind the scene.
```aiken
let x = 10
#[x, 243] // not allowed
```
However, syntax rules for literal integers also apply to byte arrays. Thus, the following is a perfectly valid syntax:
```aiken
#[0xFF, 0x42]
```
## Data
A _Data_ is an opaque compound type that can represent any possible user-defined type in Aiken. We'll see later how Aiken lets you compose your own types from the primitives we just presented. In the meantime, think of _Data_ as a kind of wildcard that can possibly represent _any_ value.
This is useful when you need to use values from different types in an homogeneous structure. Any user-defined type can be cast to a _Data_, and you can try converting from a _Data_ to any custom type in a safe manner.
Besides, several language builtins only work with _Data_ as a way to deal with polymorphism.
We'll see more about _Data_ when we cover custom types.
## Tuples
Aiken has tuples which can be useful for grouping values. Each element in a tuple can have a different type.
```aiken
(10, "hello") // Type is (Int, String)
(1, 4, [0]) // Type is (Int, Int, List(Int))
```
Long tuples (i.e. more than 3 elements) are usually discouraged. Indeed, tuples are anonymous constructors, and while they are quick and easy to use, they often impede readability. When types become more complex, one should use records instead (as we'll see later).
Elements of a tuple can be accessed using the dot, followed by the index of the element (0-based indexing). So for example:
```aiken
let point = (14, 42)
let x = point.0
let y = point.1
(y, x) // (42, 14)
```
## List
Lists are ordered collections of values. They're one of the most common data structures in Aiken.
Unlike tuples, all the elements of a List must be of the same type. Attempting to make a list using multiple
different types will result in a type error.
```aiken
[1, 2, 3, 4] // List(Int)
["text", 3, 4] // Type error!
```
Inserting at the front of a list is very fast, and is the preferred way to add new values.
```aiken
[1, ..[2, 3]] // [1, 2, 3]
```
Note that all data structures in Aiken are immutable so prepending to a list does not change the original list. Instead it efficiently creates a new list with the new additional element.
```
let x = [2, 3]
let y = [1, ..x]
x // [2, 3]
y // [1, 2, 3]
```

View File

@ -1,61 +0,0 @@
# Variables & Constants
## Variables
Aiken has let-bindings for variables. A value can be given a name using the keyword `let`.
Names can be reused by later let-bindings.
Values assigned to let-bindings are immutable, however new bindings can shadow
previous bindings.
```aiken
let x = 1
let y = x
let x = 2
y + x == 3
```
## Constants
Let-bindings aren't allowed in a top-level Aiken module. Yet, Aiken provides
module constants as a way to use certain fixed values in multiple places of a
Aiken project.
```aiken
const start_year = 2101
const end_year = 2111
```
Like all values in Aiken, constants are immutable. They cannot be used as global mutable state. When a constant is referenced, its value is inlined by the compiler so they can be used in any place where you'd have written a literal in the first place (e.g. when-expression guards, if clauses ...). We'll see some example of that when dealing with control flows.
## Type annotations
Variables and constants can be given type annotations. These annotations serve as documentation or can be used to provide a more specific type than the compiler would otherwise infer.
```aiken
const name: String = "Aiken"
const size: Int = 100
let result: Bool = 14 > 42
```
## assert
Sometimes, it is useful to fail the exit and fail the execution of a program
early on. This is where the `assert` keywords comes in handy. `assert` causes
the script to fail if it fails to bind a given expression.
It is particularly useful when combined with custom types that can have
multiple constructors, and that are expected to have a very specific shape. It
is primarily used for validating datums and redeemers -- which can really be
anything.
Having ways to enforce that some inputs have the requested shape is thus
often necessary. For example, let's consider we have a custom type `MyDatum`
that we want to turn some opaque `Data` into. We can do the following:
```aiken
// some_data : Data
assert my_datum : MyDatum = some_data
```

View File

@ -1,9 +0,0 @@
# Resources
Below is a list of links to resources we used while building Aiken.
- [The Gleam's compiler](https://github.com/gleam-lang/gleam);
- [The Official Plutus documentation](https://plutus.readthedocs.io/en/latest/);
- [The source code about encoding/Decoding UPLC](https://github.com/input-output-hk/plutus/blob/9538fc9829426b2ecb0628d352e2d7af96ec8204/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Core/Instance/Flat.hs);
- [The source code about core types](https://github.com/input-output-hk/plutus/blob/9538fc9829426b2ecb0628d352e2d7af96ec8204/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Core/Type.hs);
- [The original (albeit outdated) Plutus Core specification](https://hydra.iohk.io/build/14133599/download/1/plutus-core-specification.pdf)

View File

@ -1,23 +0,0 @@
# Untyped Plutus Core
One key feature of Aiken is how it helps you manipulate Untyped Plutus Core
(abbrev. UPLC in short). UPLC is ultimately the format whereby codes gets
executed on-chain. This is pretty-much as low-level as you can get when it
comes to Cardano smart-contracts.
Understanding how UPLC works, and having the right tools to troubleshoot
UPLC programs can be handy when developing contracts on Cardano. Fortunately,
this is something Aiken can help you with.
> **Note**
>
> While UPLC has erased any _explicit_ notion of types; functions, variables and
> constants are still _implicitly_ typed and, an interpreter will raise errors
> when encountering a type mismatch.
>
> For the sake of simplicity, we might speak about the type-signature of
> builtin functions such as `addInteger` which, in principle, only has a
> concrete meaning in Typed Plutus Core. Hence, even though they are _untyped_,
> we often think of UPLC programs has having implicit types, as if they were
> originally _typed_ programs whose types had simply been erased (in fact,
> that's exactly what they are).

View File

@ -1,75 +0,0 @@
# Builtins
| Builtins | Type Args | Term Args | Result |
| --- | --- | --- | --- |
| `ifThenElse`[^1] | \\(α\\) | (bool, \\(α\\), \\(α\\)) | \\(α\\) |
| --- | --- | --- | --- |
| `addInteger` | \- | (integer, integer) | integer |
| `subtractInteger` | \- | (integer, integer) | integer |
| `multiplyInteger` | \- | (integer, integer) | integer |
| `divideInteger` | \- | (integer, integer) | integer |
| `modInteger` | \- | (integer, integer) | integer |
| `quotientInteger` | \- | (integer, integer) | integer |
| `remainderInteger` | \- | (integer, integer) | integer |
| `equalsInteger` | \- | (integer, integer) | bool |
| `lessThanInteger` | \- | (integer, integer) | bool |
| `lessThanEqualsInteger` | \- | (integer, integer) | bool |
| --- | --- | --- | --- |
| `appendString` | \- | (string, string) | string |
| `emptyString` | \- | (string) | bool |
| `equalsString` | \- | (string, string) | bool |
| `encodeUtf8` | \- | (string) | bytestring |
| --- | --- | --- | --- |
| `appendByteString` | \- | (bytestring, bytestring) | bytestring |
| `consByteString` | \- | (integer, bytestring) | bytestring |
| `indexByteString` | \- | (bytestring, integer) | integer |
| `sliceByteString` | \- | (integer, integer, bytestring) | bytestring |
| `lengthOfByteString` | \- | (bytestring) | integer |
| `equalsByteString` | \- | (bytestring, bytestring) | bool |
| `lessThanByteString` | \- | (bytestring, bytestring) | bool |
| `lessThanEqualsByteString` | \- | (bytestring, bytestring) | bool |
| `decodeUtf8` | \- | (bytestring) | string |
| --- | --- | --- | --- |
| `chooseData`[^2] | \\(α\\) | (data, \\(α\\), \\(α\\), \\(α\\), \\(α\\), \\(α\\)) | \\(α\\) |
| `constrData` | \- | (integer, list data) | data |
| `unConstrData` | \- | data | (integer, list data) |
| `iData` | \- | (integer) | data |
| `unIData` | \- | (data) | integer |
| `bData` | \- | (bytestring) | data |
| `unBData` | \- | (data) | bytestring |
| `mapData` | \- | (list (pair data data)) | data |
| `unMapData` | \- | (data) | list (pair data data) |
| `listData` | \- | (list data) | data |
| `unListData` | \- | (data) | list data |
| `equalsData` | \- | (data, data) | bool |
| `serialiseData` | \- | (data) | bytestring |
| --- | --- | --- | --- |
| `chooseList`[^3] | \\(α, β\\) | (list \\(α\\), \\(β\\), \\(β\\)) | \\(β\\) |
| `mkNilData` | \\(α\\) | (unit) | list \\(α\\) |
| `mkCons` | \\(α\\) | (\\(α\\), list \\(α\\)) | list \\(α\\) |
| `headList` | \\(α\\) | (list \\(α\\)) | \\(α\\) |
| `tailList` | \\(α\\) | (list \\(α\\)) | list \\(α\\) |
| `nullList` | \\(α\\) | (list \\(α\\)) | bool |
| --- | --- | --- | --- |
| `mkPairData` | \\(α, β\\) | (\\(α\\), \\(β\\)) | pair \\(α\\) \\(β\\) |
| `fstPair` | \\(α, β\\) | pair \\(α\\) \\(β\\) | \\(α\\) |
| `sndPair` | \\(α, β\\) | pair \\(α\\) \\(β\\) | \\(β\\) |
| --- | --- | --- | --- |
| `sha2_256` | \- | (bytestring) | bytestring |
| `sha3_256` | \- | (bytestring) | bytestring |
| `blake2b_256` | \- | (bytestring) | bytestring |
| --- | --- | --- | --- |
| `verifyEd25519Signature`[^4] | \- | (bytestring, bytestring, bytestring) | bytestring |
| `verifyEcdsaSecp256k1Signature`[^4] | \- | (bytestring, bytestring, bytestring) | bytestring |
| `verifySchnorrSecp256k1Signature`[^4] | \- | (bytestring, bytestring, bytestring) | bytestring |
| --- | --- | --- | --- |
| `error` | \\(α\\) | (unit) | \\(α\\) |
| `trace` | \\(α\\) | (string, \\(α\\)) | \\(α\\) |
[^1]: Returns the second argument when the predicate is `True`, and the third argument when `False`.
[^2]: Each argument corresponds to each of the constructors of a builtin data (in this order): constr, map, list, integer and bytestring. The evaluation will continue with whatever branch actually corresponds to the given term value.
[^3]: Returns the second argument when the list is empty, and the third argument otherwise.
[^4]: Arguments are respectively: the public key, the message and the signature

View File

@ -1,128 +0,0 @@
# Command-line utilities
## Evaluation
Let's consider the following basic program:
<p align="right"><strong>program_1.uplc</strong></p>
```
(program
2.0.0
[ [ (builtin addInteger) (con integer 16) ] (con integer 26) ]
)
```
We can evaluate this program using Aiken's cli via:
```console
$ aiken uplc eval program_1.uplc
```
```
Result
------
(con integer 42)
Costs
-----
cpu: 321577
memory: 602
Budget
------
cpu: 9999678423
memory: 13999398
```
The output indicates the result of the evaluation (`42`) as well as the
execution cost of that program, both in terms of CPU and memory usage.
Note that the command also accepts arguments. So, for example, if we modify our
program into a function that accepts an argument as follows:
<p align="right"><strong>program_2.uplc</strong></p>
```
(program
2.0.0
(lam x [ [ (builtin addInteger) (con integer 16) ] x ])
)
```
You can then instrument Aiken to provide arguments upon calling the program by
simply appending them to the `eval` command:
```console
$ aiken uplc eval program_2.uplc "(con integer 26)"
```
```
Result
------
(con integer 42)
```
## Formatting
Because writing UPLC by hand can be a tedious task, Aiken provides a quick way to automatically format
a UPLC program via the `fmt` command. By default, the command override the file given as input, but you
can also simply prints the result to stdout using `--print`. For example:
```console
$ aiken uplc fmt program_2.uplc --print
```
```
(program
2.0.0
(lam x [ [ (builtin addInteger) (con integer 16) ] x ])
)
```
## Converting to/from bytecode
So far, we've been representing UPLC programs using a high-level syntax. In
practice, however, UPLC programs are compiled into bytecode when submitted
on-chain.
Aiken provides means to convert a high-level UPLC program into a low-level flat
bytecode and vice-versa, via the `flat` and `unflat` commands. For example:
```console
$ aiken uplc flat program_1.uplc --print
```
```
00000010 00000000 00000000 00110011
01110000 00001001 00000001 00000010
01000000 01101001
```
The `--print` flag instruments the command-line to print everything on stdout
in a readable way. Without the flag, the command creates a file `program_1.flat`
next to `program_1.uplc`.
> **Note**
>
> `aiken uplc flat program.uplc`
>
> and
>
> `aiken uplc flat program.uplc --out program.flat`
>
> are therefore equivalent.
From there, one can recover a UPLC high-level syntax from a flat program using
`unflat` as such:
```console
$ aiken uplc unflat program_1.flat --print
```
```
(program
2.0.0
[ [ (builtin addInteger) (con integer 16) ] (con integer 26) ]
)
```

View File

@ -1,78 +0,0 @@
# Syntax
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](https://hydra.iohk.io/build/14133599/download/1/plutus-core-specification.pdf).
## Primitive Types
Plutus Core has 7 primitive types (a.k.a. constants): `unit`, `bool`, `integer`, `bytestring`, `string`, `pair` and `list`.
One can construct constants using the `con` keyword, followed by the name of the primitive type and its value.
- Unit is denoted `()`;
- Bool are `True` or `False`;
- 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 `[` and `]`.
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 `<` and `>`.
| Primitive Type | Example |
| --- | --- |
| `unit` | `con unit ()` |
| `bool` | `con bool True` |
| `integer` | `con integer 42` |
| `bytestring` | `con bytestring #41696b656e` |
| `string` | `con string "Aiken"` |
| `pair` | `con pair<bool, integer> [True, 42]` |
| `list` | `con list<bytestring> [#00, #aa]` |
## Functions
A function (or simply, lambda) is constructed with the keyword `lam` followed
by a variable name, and a term (i.e. a constant, another function, etc..). One
can apply variables to a function using squared brackets `[ ]`.
For example: `[ (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: `42`.
## Builtins
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. The complete list of builtins
is given [in annexe](./builtins.md).
## 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.
- `force` can be used on a polymorphic function to instantiate one type-parameter. For example, the branches of a builtin `ifThenElse` can be of any type -- though they have to be the same for both branches. In fact, `ifThenElse` has one type parameter. To be called, it must therefore be forced once: `[ [ [ force (builtin ifThenElse) p ] x ] y ]`
- Similarly, `delay` can 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.
## Data
In addition to primitive types, Plutus Core also has a more generalized `data`
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](https://github.com/txpipe/aiken/issues/34)
> since the introduction of "list" and "pair" keywords may come in handy.
## Programs
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
(`2.0.0`).