GithubHelp home page GithubHelp logo

typetheory's Introduction

(ITALIANO: Note del corso di Teoria dei Tipi: qui)

Agda Tutorials:

  1. Commands
  2. Types and Functions
  3. Framework for defining functions
  4. Lists and Vectors
  5. Module System
  6. Proving lemmas with Witnesses
  7. Step for proving lemmas (Equality)
  8. Keyword #1: where
  9. Keyword #2: rewrite
  10. Keyword #3: with
    9.1 if... else
  11. Decidability

Command Input Combination
Compile $\to$ Ctrl-C Ctrl-L
Run $\to$ Ctrl-C Ctrl-N
Case Assist $\to$ Ctrl-C Ctrl-C
Remove hole $\to$ Ctrl-C Ctrl-␣
Type hint $\to$ Ctrl-C Ctrl-,
Automatic Proof Search (Auto) $\to$ Ctrl-C Ctrl-A

1. Basic Types and Functions

1.1 Define Types:

Syntax:

data $NAME : Set where
    $(elements of the Type)

Example: Natural Numbers ℕ

data  : Set where -- ℕ = \bN
  -- base element (0)
  zero :-- function succ is a generic function from
  -- ℕ → ℕ, in our conception
  -- succ zero              → 1
  -- succ (succ zero)       → 2
  -- succ (succ (succ zero) → 3
  succ :

1.2 Define Functions:

Syntax:

$functionname : Type (Input)  Type (Output)
$functionname ... ($what_the_function_does)

Example: Add 1 to a Natural Number

add1 : ℕ
add1 n = succ n

Agda can only support only one argument for its functions, however we can implement multiple arguments as follows:

add : ℕ
add zero b = b
add (succ a) b = succ (a + b)

By pressing Ctrl-C Ctrl-N we can test the funciton:

>> add (succ zero) (succ (succ zero))
succ (succ (succ zero))

We just added the successor of zero (one) and the successor of the successor of zero (two) and we got the successor of the successor of the successor of zero.

With the help of the underscores we can suggest Agda where to place our function with respect to the arguments:

_+_ : ℕ
zero + b = b
succ a + b = succ (a + b)

Now we can place the two arguments around the "+" sign:

>> (succ zero) + (succ (succ zero))
succ (succ (succ zero))

2. Framework for defining functions:

Defining functions can be eased by the use of Short-cuts. Example: AND function for Booleans: First we define the Boolean type:

data Bool : Set where
  true  : Bool
  false : Bool

Here we start defining the function _&&_ just as in 1.2:

_and_ : Bool  Bool  Bool
a and b = ?

If we type the generic arguments and the result as ? and then compile (Ctrl-C Ctrl-L), a hole will be generated:

_and_ : Bool  Bool  Bool
a and b = { }0

We can let Agda find by itself find all the possible case-scenarios of the function and by typing in the hole Ctrl-C Ctrl-C:

pattern variables to case (empty for split on result):
>> a

If we type a (the first argument) Agda will automatically create all the possible scenarios concerning that variable

_and_ : Bool  Bool  Bool
true and b  = { }0
false and b = { }1

If we repeat it for the b argument in the { }0 and { }1 holes we get to:

_and_ : Bool  Bool  Bool
true and true   = { }0
true and false  = { }1
false and true  = { }2
false and false = { }3

From here we can fill all the hole with the answers we know:

_and_ : Bool  Bool  Bool
true and true   = {true }0
true and false  = {false }1
false and true  = {false }2
false and false = {false }3

The holes can be dissolved by typing Ctrl-C Ctrl-␣ when inside it.

3. Lists and Vectors

Lists:

-- List is an object of a given type (A)
data List (A : Set) : Set where
  -- base element (empty list)
  []  : List A
  -- prepend function prepend(x, list) = [x,list]
  _∷_ : A  List A  List A

list_example : List ℕ -- with ℕ we declare its element will be naturals
list_example = (succ (succ (succ zero))) ∷ ((succ (succ zero)) ∷ (succ zero ∷ []))
--           = [3,2,1]

Vectors: (they have a fixed lenght stated in the initialization)

data Vector (A : Set) : Set where
  []  : Vector A zero
  _∷_ : {n : ℕ}  A  Vector A n  Vector A (succ n)

vector_example : Vector ℕ (succ (succ (succ zero)))
vector_example = zero ∷ ((succ zero) ∷ ((succ (succ (succ zero))) ∷ []))

For examples of applications of functions to Vectors and Lists see ./EX2_Lists_n_Vectors

4. Module System

When building large programs it is crucial to be able to split the program over multiple files and to not have to type check and compile all the files for every change. The module system offers a structured way to do this.

Assume you are working in a file called main.agda and you need to access Types and Functions in other files imports/naturals.agda and imports/booleans.agda

root
│   main.agda  
│
└───imports
    |   naturals.agda
    |   booleans.agda

The files in the import folder in which we define the helping functions and types must be formatted as it follows

module import.$filename where
  ...

For example:

module imports.naturals where
  data ℕ : Set where
    zero :succ : ℕ

  one = succ zero

  add1 : ℕ
  add1 a = succ a

In order to use the code in main.agda from the imported folder we need to tell to import them. In main.agda

open import imports.naturals
open import imports.booleans

Now we can use the Types and Functions as it they where in the file:

>> add1 zero
succ zero

5. Proving lemmas with Witnesses

In Agda (and in Type Theory) proving something means that the relative type of what we want to prove is inhabited. Namely if we want to prove that "four is an even number" we can construct the type Four is even and verify wether it is inhabited or not.

Example:

What is the Type "four is an even number"?

1.Construct the Even data type which takes a natural number as input and outputs a set:

data Even : Set where
  Base-even : Even zero                               -- "the number zero is even"
  Step-even : (n : ℕ)  Even n  Even (succ (succ n)) -- "for every number n, if n
                                                      -- is even so is
                                                      -- succ (succ n)"

The data type Even contains two elements:

  • Base-even which is a witness that zero is even.
  • Step-even that states that if we have a witness of the type Even n, then it next next successor is Even too, therefore another witness for another number.

Now if we cast Even four, this is a type.

  1. We can start proving that zero is even, next that two is even and then that four is even:
zero-is-even : Even zero
-- the witness that zero is even is the base element of the Even type
zero-is-even = Base-even

two-is-even : Even two
-- if zero is even (which we know as the base even number) then is next
-- next successor is an even too.
-- Step-even takes in input two elements:
--          1. a natural number n
--          2. the witness (proof) that that natural number is even
-- and then it outputs the witness that two is a natural number
two-is-even = Step-even zero Base-even

four-is-even : Even four
four-is-even = Step-even two (two-is-even)

Similarly we can prove that "three is an Odd number":

data Odd : Set where
  Base-odd : Odd one
  Step-odd : (n : ℕ)  Odd n  Odd (succ (succ n))

one-is-odd : Odd one
one-is-odd = Base-odd

three-is-odd : Odd three
three-is-odd = Step-odd one Base-odd

6. Proving lemmas (Equality)

In Agda:

  • The ordinary equality sign '=' is for definitions.
  • In contrast, '≡' is the customary notation in the comunity for observations, results.

But first we have to define what '≡' is. Agda does not know about that yet. Here we define it for natural numbers, but it can be easily extended for any set.

data _≡_ : Set where
  -- every given thing is equal to itself
  refl : {a : ℕ}  (a ≡ a)   -- "reflexivity"

The only property we require from is refleivity, namely that for every number a, a is equal to a.

Just from this only property, the other basic properties can be defined:

  1. congruence: If x and y are equal, any function applied to them must return equal values:
cong : {A B : Set} {x y : A}  (f : A  B)  x ≡ y  f x ≡ f y
cong f refl = refl
  1. symmetry: If x is equal to y, y is equal to x:
symm : {A : Set} {x y : A}  x ≡ y  y ≡ x
symm refl = refl
  1. transitivity: If x is equal to y and y is equal to z, x is equal to z:
trans : {A : Set} {x y z : A}  x ≡ y  y ≡ z  x ≡ z
trans refl p = p

Example 1: Proving (a + zero) ≡ a

First we need to define the basic stuff:

-- Natural Numbers
data  : Set where
  zero :succ :-- Addition
_+_ : ℕ
zero   + b = b
succ a + b = succ (a + b)

-- Equality
data _≡_ {X : Set} : X  X  Set where
  refl : {a : X}  a ≡ a

-- Equality: Congruence Property
cong : {A B : Set} {x y : A}  (f : A  B)  x ≡ y  f x ≡ f y
cong f refl = refl

-- Equality: Symmetry Property
symm : {A : Set} {x y : A}  x ≡ y  y ≡ x
symm refl = refl

-- Equality: Transitivity Property
trans : {A : Set} {x y z : A}  x ≡ y  y ≡ z  x ≡ z
trans refl p = p

Now we go to proving the lemma:

  1. Name the lemma and state what you want to prove:
lemma-+-zero : (a : ℕ) → (a + zero) ≡ a
  1. Add the general template:
lemma-+-zero : (a : ℕ)  (a + zero) ≡ a
lemma-+-zero a = ?
  1. Compile (Ctrl-C Ctrl-L):
lemma-+-zero : (a : ℕ)  (a + zero) ≡ a
lemma-+-zero a = { }0

This created a hole which can be filled anytime

  1. Try a case split, since we only have a single parameter (a) we split a (Inside the hole: Ctrl-C Ctrl-C)
pattern variables to case (empty for split on result): a
lemma-+-zero : (a : ℕ)  (a + zero) ≡ a
lemma-+-zero zero = { }0
lemma-+-zero (succ a) = { }1
  1. Get some insights of the holes: (Inside the hole 0, Ctrl-C Ctrl-,)
Goal: zero ≡ zero

Here we need to prove something we already define in , namely refl

lemma-+-zero : (a : ℕ)  (a + zero) ≡ a
lemma-+-zero zero = {refl }0
lemma-+-zero (succ a) = { }1

(Inside the hole 1, Ctrl-C Ctrl-,)

Goal: succ (a + zero) ≡ succ a

Which is basically the lemma we want to prove, but with succ in front of both term, this calls for congruence:

lemma-+-zero : (a : ℕ)  (a + zero) ≡ a
lemma-+-zero zero = {refl }0
lemma-+-zero (succ a) = {cong succ (lemma-+-zero a) }1
```agda
lemma-+-zero : (a : ℕ)  (a + zero) ≡ a
lemma-+-zero zero = {refl }0
lemma-+-zero (succ a) = {cong succ (lemma-+-zero a) }1
  1. Remove the holes with Ctrl-C Ctrl-␣
lemma-+-zero : (a : ℕ)  (a + zero) ≡ a
lemma-+-zero zero = refl
lemma-+-zero (succ a) = cong succ (lemma-+-zero a)

The holes will be eliminated only if the demonstration is consistent, now that this lemma is considered proven we can use it to proves other lemmas and so on...

Example 2: A more complicated example:

Assuming we also demonstrated the following lemma:

lemma-+-succ : (a b : ℕ)  (a + succ b) ≡ succ (a + b)
lemma-+-succ zero b = refl
lemma-+-succ (succ a) b = cong succ (lemma-+-succ a b)

Now we want to demonstate the commutative property of the addition:

lemma-+-commutative : (a b : ℕ)  (a + b) ≡ (b + a)
lemma-+-commutative a b = ?

(Case split in a)

lemma-+-commutative : (a b : ℕ)  (a + b) ≡ (b + a)
lemma-+-commutative zero b = { }0
lemma-+-commutative (succ a) b = { }1

zero case asks for the following proof (Ctrl-C Ctrl-,):

Goal: (b : ℕ) → b ≡ (b + zero)

Which is quite the lemma-+-zero but on the other way around:

lemma-+-commutative : (a b : ℕ)  (a + b) ≡ (b + a)
lemma-+-commutative zero b = symm (lemma-+-zero b)
lemma-+-commutative (succ a) b = { }0

The next hole is rather less trivial, it asks for:

Goal: succ (a + b) ≡ (b + succ a)

We basically need to go from the left-hand side succ (a + b) to the right-hand side (b + succ a) using only lemmas and properties we already demonstrated/defined. For this example, the steps are:

  1. succ (a + b) ---> succ (b + a) thanks to lemma-+-commutative a b
  2. succ (b + a) ---> (a + succ b) thanks to symm lemma-+-succ b a This translates to:
lemma-+-commutative : (a b : ℕ)  (a + b) ≡ (b + a)
lemma-+-commutative zero b = symm (lemma-+-zero b)
lemma-+-commutative (succ a) b = trans (cong succ (lemma-+-commutative a b)) (symm (lemma-+-succ b a))

For other demonstrations of lemmas about equality see ./EX4_Equality.agda

7. Special keyword #1 : where

where is the first special keyword, is use is to carry simple lemmas into a bigger demonstration. Let us see it with an example:

Suppose we already introduced Natural Numbers Nat, the operation of addition _+_ and the equality relation _≡_:

-- We want to demonstrate the trivial folowing relation
theorem : {a : ℕ}  (succ a + a) ≡ succ (a + a)
theorem {a} = ?

To demonstare it, cong property of the equivalence may come in handy:

cong : {A : Set}  {x y : A}  (f : A  A)  (x ≡ y)  (f x ≡ f y)
cong f refl = refl

theorem : {a : ℕ}  (succ a + a) ≡ succ (a + a)
theorem {zero}   = refl
theorem {succ a} = cong succ refl

We could have written the above demonstration using where:

theorem' : {a : ℕ}  (succ a + a) ≡ succ (a + a)
theorem' {zero} = refl
theorem' {succ a} = cong' succ refl -- at this line cong' is not defined, 
                                    -- we carry its definition below using
                                    -- with:
  where
  cong' : {A : Set}  {x y : A}  (f : A  A)  (x ≡ y)  (f x ≡ f y) 
  cong' f refl = refl

8. Special keyword #2 : rewrite

???

9. Special keyword #3 : with

with is used to consider many possibilities a data type may have. Also it is almost essential to some recursive demonstrations:

As an example, let us demonstrate that a given number is either even or odd.

Let us define the required types:

data Even : Set where
  base-even : Even zero -- base element
  step-even : {n : ℕ}  Even n  Even (succ (succ n))

data Odd : Set where
  base-odd : Odd (succ zero) -- base element
  step-odd : {n : ℕ}  Odd n  Odd (succ (succ n))

data _⊎_ (A B : Set) : Set where
  left  : A  A ⊎ B
  right : B  A ⊎ B

And let us assume that we already demonstrated that if we have an odd number, its successor is even and viceversa:

lemma-succ-even : (a : ℕ)  (Even a)  Odd (succ a)
lemma-succ-even zero base-even    = base-odd
lemma-succ-even (succ (succ a)) (step-even p) = step-odd (lemma-succ-even a p)

lemma-succ-odd : (b : ℕ)  (Odd b)  Even (succ b)
lemma-succ-odd (succ zero) base-odd = step-even base-even
lemma-succ-odd (succ (succ b)) (step-odd p) = step-even (lemma-succ-odd b p)
lemma-even-odd : (a : ℕ)  Even a ⊎ Odd a
lemma-even-odd zero = left base-even
lemma-even-odd (succ a) = { }0

The goal here is to demonstrate that succ a is in Even a ⊎ Odd a, but the witness of it (left or right) depends on a, its precedessor. Let us use with

lemma-even-odd : (a : ℕ)  Even a ⊎ Odd a
lemma-even-odd zero = left base-even
lemma-even-odd (succ a) with lemma-even-odd a
...| left  p = { }0 -- p : Odd a
...| right p = { }1 -- p : Even a

Basically we want to demonstrate that succ ais inEven a ⊎ Odd a` given that (with) lemma-even-odd a holds in the two possible scenarios (Odd a and Even a).

lemma-even-odd : (a : ℕ)  Even a ⊎ Odd a
lemma-even-odd zero = left base-even
lemma-even-odd (succ a) with lemma-even-odd a
...| left  p = right (lemma-succ-even a p)
...| right p = left (lemma-succ-odd a p)

9.1. Special keyword #3 : with as if... else

Agda does not really have if... else statements, the closest structure to that is with in Agda Example: Filter list

data Bool : Set where
  true  : Bool
  false : Bool

data  : Set where
  zero :succ :-- Define a function that returns false if
-- the argument integer is zero, truìe otherwise
not-zero : Bool
not-zero zero = false
not-zero (succ n) = true

-- Arguments:
-- > A → Bool filer function
-- > List A list to filter
filter : {A : Set}  (A  Bool)  List A  List A
filter p [] = []
filter p (x ∷ xs) with p x
...    | true  = x ∷ filter p xs
...    | false = filter p xs

-- natural-vector = [3,0,2,0,1,0]
natural-vector = (succ (succ (succ zero))) ∷ 
                 (zero ∷ (succ (succ zero) ∷
                 (zero ∷ (succ zero ∷ (zero ∷ [])))))
>> filter not-zero natural-vector
succ (succ (succ zero)) ∷ (succ (succ zero) ∷ (succ zero ∷ []))
-- [3,2,1]

Example: Compare numbers You can abstract over multiple terms in a single with-abstraction. To do this you separate the terms with vertical bars |.

data Bool : Set where
  true  : Bool
  false : Bool

data Comparison : Set where
  greater : Comparison
  less    : Comparison
  equal   : Comparison

data  : Set where
  zero :succ :_<_ : (a : ℕ)  (b : ℕ)  Bool
zero < zero     = false
zero < (succ b) = true
(succ a) < zero = false
(succ a) < (succ b) = a < b

one = succ zero
two = succ one
three = succ two
four = succ three
five = succ four

compare : Comparison
compare x y with x < y | y < x
...            | true  | _     = less
...            | _     | true  = greater
...            | false | false = equal
>> compare two one
greater
>> compare one three
less
>> compare four four
equal

10. Decidability

"Decidability in CS is the property (some properties) that there are machines which are able to find out wether that property holds or not" Decidable properties : Examples:

  • property that a natural number being a prime number
  • property that a number to be positive or zero

Non-decidable properties : Examples:

  • property that a given function from ℕ to ℕ to have a zero (for this you would need to simulate the input for all possible natural number, which requires an infinite amount of time, just because to prove that a given function does NOT have a zero, you need to try every possible natural number)

How can this be formalized in Agda?

-- "Dec A" is the type of witnesses that A is decidable:
data Dec (A : Set) : Set where 
  yes :   A  Dec A 
  no  : ¬ A  Dec A 

There are two kinds of inhabitands of that type. If you want to verify A, you can (at your own choosing) either verify A or ¬ A.

Example: Positivity is decidable

data Positive : Set where
  succs-are-positive : (a : ℕ)  Positive (succ a)

positivity-is-decidable : (a : ℕ)  Dec (Positive a)
positivity-is-decidable zero      = ?
positivity-is-decidable (succ a)  = yes (succs-are-positive a) 

What do we put for zero in ?? For a moment let us try to fill that hole with a yes

positivity-is-decidable : (a : ℕ)  Dec (Positive a)
positivity-is-decidable zero      = yes ?
positivity-is-decidable (succ a)  = yes (succs-are-positive a) 

Now in ? we need a witness that zero is positive, which we are not able to.

data Positive : Set where
  succs-are-positive : (a : ℕ)  Positive (succ a)

positivity-is-decidable : (a : ℕ)  Dec (Positive a)
positivity-is-decidable zero      = no  (λ ()) 
positivity-is-decidable (succ a)  = yes (succs-are-positive a) 
-- "Every inhabited set of natural numbers contains a mininmum"
-- this is true
-- We can picture a function P : ℕ → Set as a set of natural numbers
-- namely, the number n belongs to this set if and only if P n is
-- inhabited, hence P n is the type of witnesses that n belongs to the set.
data _≤_ (P : Set)  (a₀ : ℕ)  P a₀ -- fill this in

-- function that computes the minimum
minimum : (P : Set)  (a₀ : ℕ)  P a₀  ℕ
minimum = ?

-- function that verify that the minimum is
-- computed correctly
lemma-minimum-is-computed-correctly
  : (P : Set)  (a₀ : ℕ)  (p : P a₀)
   (n : ℕ)  P n  a₀ ≤ n 
lemma-minimum-is-computed-correctly = ?

The two holes cannot be filled, intuitively: if the given minimum given a₀ is zero we are done. If it is greater than zero we would need to check wether there is a smaller number in the Set, which cannot be mechanically done.

typetheory's People

Contributors

saveriomonaco avatar

Stargazers

 avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.