- enumeration type is an inductive type whose all constructors have zero arguments
- always use the formatter
- don't use unicode, except perhaps for judoc
- avoid
Pair - prefer enumeration types with meaningful constructor names over booleans,
e.g., instead of using
Booldefine:
type Transferability :=
| Transferable
| NonTransferable;
- all imports at the beginning of the file
- explicit names for imported identifiers (
import X open using {iden1; iden2})- exception:
import Stdlib.Prelude openandimport Anoma openare allowed
- exception:
- types: upper camel case (
Nat,PublicKey) - functions, constructors, etc: lower camel case (
tokenLogic,transferLogic)- exception: constructors of enumeration types: upper camel case
type BalanceFactor :=
| --- Left child is higher.
LeanLeft
| --- Equal heights of children.
LeanNone
| --- Right child is higher.
LeanRight;
type Ordering :=
| LessThan
| Equal
| GreaterThan;
- instances: lower camel case with
Iat the end: trait + type +I, e.g.,instance eqNatI : Eq Nat := .. - boolean check functions: start with
is(isWhatever) - record constructors:
mk+ type name (mkResource) - meaningful descriptive long names for arguments of public functions, e.g.,
element,list,initialValue- exception: common abbreviations allowed:
fun,acc,elem - exception: generic functions whose arguments have no specific meaning, e.g.,
- exception: common abbreviations allowed:
id {A} (x : A) : A := x
- short names like
xare okay for local definitions
- put everything to the left of
:in type signatures, with full meaningful names for arguments- temporary exception: when needed for termination, argument can be moved to the right of
: - even when the argument type is moved to the right, give a descriptive argument name in the type:
- temporary exception: when needed for termination, argument can be moved to the right of
isMember {A} (testEq : A -> A -> Bool) (element : A) : (list : List A) -> Bool
- type variables uppercase (upper camel case, like with types)
- higher-order type variables also upper camel case (
F : Type -> Type) - implicit type variables: use short version
{A}in function signatures on the left - prefer
{A B}over{A} {B}in function signatures - meaningful type variable names for more "high-level" functions where this makes sense
Example:
split
{ResourceType}
{{Convertable ResourceType}}
{{HasOwner ResourceType}}
{{HasQuantity ResourceType}}
{{HasTransferability ResourceType}}
{{TransactionConvertable ResourceType ResourceType}}
(self : KeyPair)
(toSplit : ResourceType)
(quantitiesAndReceivers : List (Pair Nat PublicKey))
: Result StandardError Transaction :=
...
But we can use a short name A in:
find {A} (predicate : A -> Bool) : (list : List A) -> Maybe A
- use
casewhenever possible; matching on multiple values handled with pairs - don't use pattern matching with side conditions when there is an
elseside condition -- convert to anifin the body instead - don't pattern match on
Bool-- useifinstead
- don't use "pipes" (i.e.,
|>,<|,>>,<<, etc.)- exception: there is a "natural" data processing pipeline in several steps, e.g.,
map (+ 1) >> filter (< 0) >> sum
- use iterators
for,map, etc., instead of the function application syntax withfold, etc. - use named application when reasonable
- use ADT syntax
- every constructor on a separate line
- give meaningful names to constructor arguments
Example:
type BinaryTree (A : Type) :=
| leaf
| node@{
left : BinaryTree A;
element : A;
right : BinaryTree A
};
- the documentation string should be an English sentence
- mention the meaningful argument names in the function's judoc