From e9b352bc0aef29d9306789a150670410a84a2083 Mon Sep 17 00:00:00 2001 From: mehbark Date: Sun, 17 Nov 2024 13:53:14 -0500 Subject: [PATCH] just getting started --- Cargo.lock | 7 +++++ Cargo.toml | 6 +++++ src/lib.rs | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/lib.rs diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..0a92ed5 --- /dev/null +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..4a6eaa7 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "lc-to-iota" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..4e11624 --- /dev/null +++ b/src/lib.rs @@ -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, Rc), + Iota, +} + +#[derive(Debug, PartialEq, Eq)] +pub enum LC { + Abs(Rc), + App(Rc, Rc), + Var(usize), +} + +impl LC { + pub fn app(self, x: impl Into) -> 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 { + self.free_vars_past(0) + } + + fn free_vars_past(&self, bound: usize) -> HashSet { + // 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 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)))"); +}