At one point one needs to stop talking and start typing code. This is the same as in software development. The first lines are typically boring. That’s why it’s important to look ahead and talk freely, sometimes. After knowing what we want, sometimes we can endure the boring parts.

Validators. What are validators? We don’t know much. We just say there are as many validators as there are integers. Integers in Isabelle/HOL are infinitely many.

datatype validator = Validator int

After we say this, Isabelle/HOL allows us to compare two validators and see if they are equal or not. It does not allow us to “add” or “multiply” validators. It does not allow us to ask if a validator is larger than another validator. It does not allow us to compare a validator against an integer. That’s a comfortable situation. We are protected from many mistakes.

Validators have weights. We just talk about functions that assign weights to validators.

type_synonym weight = “validator ⇒ int”

After we say this, whenever Isabelle/HOL sees weight , it does not see weight but sees validator => int , which is the type of (usual total) functions that take validators and return integers. The function just returns one integer on every validator.

Of course, we can specify properties on the weight functions.

definition tie_breaking :: “validator set ⇒ weight ⇒ bool”

where

“tie_breaking V w =

( ∀ S0 S1.

S0 ⊆ V ⟶

S1 ⊆ V ⟶

S0 ≠ S1 ⟶

sum w S0 ≠ sum w S1 )”

After typing these lines, Isabelle/HOL knows tie_breaking means something. It does not automatically replace occurrences of tie_breaking with the lengthier definition, but it’s aware that tie_breaking is defined. Some plugins even look at the content of the definitions to figure out how to (dis)prove stuff.