just getting started

This commit is contained in:
mehbark 2024-11-17 13:53:14 -05:00
commit e9b352bc0a
3 changed files with 91 additions and 0 deletions

7
Cargo.lock generated Normal file
View file

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "lc-to-iota"
version = "0.1.0"

6
Cargo.toml Normal file
View file

@ -0,0 +1,6 @@
[package]
name = "lc-to-iota"
version = "0.1.0"
edition = "2021"
[dependencies]

78
src/lib.rs Normal file
View file

@ -0,0 +1,78 @@
//! Compiles the [lambda calculus](https://en.wikipedia.org/wiki/Lambda_calculus),
//! represented by the [`LC`] type,
//! to a tree of [Iota (ι) combinators](https://en.wikipedia.org/wiki/Iota_and_Jot),
//! represented by the [`Iota`] type.
use core::fmt;
use std::{collections::HashSet, rc::Rc};
#[derive(Debug, PartialEq, Eq)]
pub enum Iota {
App(Rc<Iota>, Rc<Iota>),
Iota,
}
#[derive(Debug, PartialEq, Eq)]
pub enum LC {
Abs(Rc<LC>),
App(Rc<LC>, Rc<LC>),
Var(usize),
}
impl LC {
pub fn app(self, x: impl Into<Self>) -> Self {
Self::App(self.into(), x.into().into())
}
pub fn abs(self) -> Self {
Self::Abs(self.into())
}
pub fn has_free_vars(&self) -> bool {
// TODO: faster
!self.free_vars().is_empty()
}
// contextless free vars aren't that useful?
pub fn free_vars(&self) -> HashSet<usize> {
self.free_vars_past(0)
}
fn free_vars_past(&self, bound: usize) -> HashSet<usize> {
// TODO: faster
match self {
LC::Abs(x) => x.free_vars_past(bound + 1),
LC::App(f, x) => {
let f_vars = f.free_vars_past(bound);
let x_vars = x.free_vars_past(bound);
&f_vars | &x_vars
}
LC::Var(_) => todo!(),
}
}
}
impl From<usize> for LC {
fn from(n: usize) -> Self {
Self::Var(n)
}
}
impl fmt::Display for LC {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
LC::Abs(x) => write!(f, "(λ {x})"),
LC::App(g, x) => write!(f, "({g} {x})"),
LC::Var(n) => write!(f, "{n}"),
}
}
}
#[test]
fn lc_display() {
let identity = LC::Var(0).abs();
assert_eq!(identity.to_string(), "(λ 0)");
let apply = LC::Var(1).app(0).abs().abs();
assert_eq!(apply.to_string(), "(λ (λ (1 0)))");
}