This guide assumes that you have already read the previous parts. It is highly recommended that you do so as the higher level language is built directly on top of the lower level language.
The first difference you need to be aware of for the higher level language is that you should call
run instead of
This lets the runtime know that it should be including higher level features.
The first higher level feature you should be aware of is that it is no longer necessary to quote atoms.
Run also gives us access to a number of convenient high level operators, which we will cover now.
list takes any number of parameters and returns them put inside a list.
This saves us from having to manually create nested
(c (A) (c (B) (q ()))) calls, which can get messy quickly.
if automatically puts our
i statement into the lazy evaluation form so we do not need to worry about the unused code path being evaluated.
The advantages of this may not be immediately obvious but are extremely useful in practice as it allows us to substitute out sections of predetermined code.
Suppose we are writing a program that returns another coin's puzzle.
We know that a puzzle takes the form:
(c (c (q 50) (c (q 0xpubkey) (c (sha256tree (f (a))) (q ())))) ((c (f (a)) (f (r (a))))))
However we will want to change 0xpubkey to a value passed to us through our solution.
and takes two boolean values and returns true if both values are true
It is important to remember that in practice smart contracts will run using the lower level language, so none of the above operators will work on the network.
What we can do however is compile them down to the lower level language.
This is where
mod comes in.
mod is an operator that lets the runtime know that it needs to be compiling the code rather than actually running it.
(mod A B) takes two or more parameters. The first is used to name parameters that are passed in, and the last is the higher level script which is to be compiled.
As you can see it returns our program in compiled lower level form.
You may be wondering what other parameters
mod takes, between variable names and source code.
In the higher level language we can define functions, macros, and constants before our program by using
We can define as many of these as we like before the main source code. Usually a program will be structured like this:
A few things to note:
- Functions can reference themselves in their code but macros cannot as they are inserted at compile time, similar to inline functions.
- Both functions and macros can reference other functions, macros and constants.
- Macros that refer to their parameters must be quasiquoted with the parameters unquoted
- Be careful of infinite loops in macros that reference other macros.
- Comments can be written with semicolons
Now lets look at some example programs using functions.
We can save these files to .clvm files which can be run from the command line.
Saving the above example as
factorial.clvm allows us to do the following.
Now lets do an example which uses macros as well. When writing a macro it must be quasiquoted with the parameters being unquoted.
We can also take this time to show another feature of the compiler. You can name each parameter in a list or you can name the list itself. This works at any place where you name parameters, and allows you to handle lists where you aren't sure of the size.
Here we define a macro to square a parameter and then a function to square a list.
Compiling and running this code results in this:
You should now have the context and knoweldge needed to write your own smart contracts. Remember from part 2 that these programs run on the blockchain and instruct the blockchain what to do with the coin's value.
If you have further questions feel free to ask on Keybase.