Algebrallinen tyyppiteoria


Lainauksen säännöt

  • Jokaisella hetkellä ohjelman suorituksen aikana voi olla &T ja &mut T lainauksia...
    • Mikä tahansa lukumäärä muuttumattomia lainauksia &T
    • Tai yksi muuttuva lainaus &mut T
  • Referenssien tulee aina osoittaa validiin Tn instanssiin


Mikä on tyyppi?

  • Tieto luokitellaan tyyppeihin [i32; 5]
  • Myös funktioilla on tyyppi fn(String) -> usize
  • Tyyppi määrittelee ja rajoittaa missä muodossa tieto esiintyy
  • Esitys muistissa
  • Miten funktio on esitetty muistissa?

[i32; 5]

Algebralliset tietotyypit

  • Tulo- ja summatyypit
  • Ergonominen match
  • Konkreetti eikä abstrakti
  • Tietoon pääsee helposti käsiksi,
    koska tiellä ei ole turhia abstraktioita
    • Vertaa luokkiin ja olioihin

Tulotyyppi

T = bool × i32 × Vec<f64>

  • Tulotyypit sisältävät monta ilmentymää kerralla
    • T:n konstruktoiminen vaatii ilmentymän boolista, i32sta ja Vec<f64>sta
  • Tuplet ja structit ovat tulotyyppejä

Summatyyppi

S = A(i32) + B(String)

  • Ilmentymän variantit ovat samaa tyyppiä
  • Varianteilla on uniikki nimi
    • A ja B
  • Enumit ovat summatyyppejä
  • S ei voi sisältää i32 ja String samaan aikaan

struct

#![allow(unused)]
fn main() {
struct Person {
	age: i32,
	name: String,
}
}

Erilaisia structeja

#![allow(unused)]
fn main() {
/// tuple struct
struct S(i32, String);
}
#![allow(unused)]
fn main() {
/// unit struct
struct S;
}

enum

#![allow(unused)]
fn main() {
enum E {
  None,
  Some(i32),
  Person { name: String, age: i32 },
}
}

struct muistissa

struct S { b: B, c: C } struct S(B, C)
C B

enum muistissa

enum E { A, B, C }
Tag "A" A tai Tag "B" B tai Tag "C" C

Missä None?

yobs = {"Python": 1989, "Rust": 2010, "Prolog": 1972}
rust_birth = yobs.get("Rust") # 2010
print(rust_birth + 12)        # 2022

java_birth = yobs.get("Java") # None
print(java_birth + 27)        # Wat?

java_birth = yobs.get("Java") # None
print(java_birth + 27)        # ERROR!!!

TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'

#![allow(unused)]
fn main() {
use std::collections::HashMap;

let yobs = HashMap::from([
    ("Python", 1989),
    ("Rust", 2010),
    ("Prolog", 1972),
]);

let rust_birth = yobs.get("Rust");
println!("{:?}", rust_birth); // Some(2010)
}

HashMap::<K, V>::get

pub fn get(&self, k: &K) -> Option<&V>


let java_birth: Option<&i32> = yobs.get("Java"); // None
println!("{:?}", java_birth.map(|y| y + 12));    // None

Option<T>

#![allow(unused)]
fn main() {
enum Option<T> {
	Some(T),
	None,
}
}

Variantit eivät ole tyyppejä!


match

#![allow(unused)]
fn main() {
enum E {
	/// Unit variant
    None,
	/// Newtype variant
    Some(i32),
	/// Struct variant
    Person { name: String, age: i32 },
}

let e = E::Some(5);
match e {
    E::Some(num) => dbg!(num),
    _ => todo!(),
};
}
[src/main.rs:11] num = 5


λ-funktiot (klosuurit)

#![allow(unused)]
fn main() {
let luvut = (1..12).filter_map(
	|n| if n % 3 == 0 { Some(n * 2) } else { None }
);

for n in luvut {
    println!("{n}");
}
}

Lopuksi