diff --git a/Cargo.toml b/Cargo.toml index 3d46c86..884c87f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ readme = "README.md" license = "CC0-1.0" keywords = ["lambda", "calculus", "functional", "mathematics", "combinators"] authors = ["ljedrz "] -edition = "2021" +edition = "2024" [lib] crate-type = ["lib"] diff --git a/src/combinators.rs b/src/combinators.rs index 2bc4b06..5417600 100644 --- a/src/combinators.rs +++ b/src/combinators.rs @@ -12,7 +12,7 @@ #![allow(non_snake_case)] use crate::term::Term::*; -use crate::term::{abs, app, Term}; +use crate::term::{Term, abs, app}; /// I - the identity combinator. /// diff --git a/src/data/boolean.rs b/src/data/boolean.rs index 5e7f27d..446e086 100644 --- a/src/data/boolean.rs +++ b/src/data/boolean.rs @@ -1,7 +1,7 @@ //! [Lambda-encoded booleans](https://en.wikipedia.org/wiki/Church_encoding#Church_Booleans) use crate::term::Term::*; -use crate::term::{abs, app, Term}; +use crate::term::{Term, abs, app}; /// A lambda-encoded boolean `true`. /// @@ -179,10 +179,6 @@ pub fn imply() -> Term { impl From for Term { fn from(b: bool) -> Term { - if b { - tru() - } else { - fls() - } + if b { tru() } else { fls() } } } diff --git a/src/data/list/church.rs b/src/data/list/church.rs index 91cf8cb..9ee388b 100644 --- a/src/data/list/church.rs +++ b/src/data/list/church.rs @@ -3,7 +3,7 @@ use crate::data::boolean::{fls, tru}; use crate::data::pair::{fst, pair, snd}; use crate::term::Term::*; -use crate::term::{abs, app, Term, UD}; +use crate::term::{Term, UD, abs, app}; /// Produces a `nil`, the last link of a Church-encoded list; equivalent to `boolean::tru`. /// diff --git a/src/data/list/convert.rs b/src/data/list/convert.rs index 37c4a0b..810416b 100644 --- a/src/data/list/convert.rs +++ b/src/data/list/convert.rs @@ -2,9 +2,11 @@ #![allow(missing_docs)] +use alloc::vec::Vec; + use crate::data::num::convert::*; use crate::term::Term::*; -use crate::term::{abs, app, Term}; +use crate::term::{Term, abs, app}; macro_rules! make_trait { ($trait_name:ident, $function_name:ident) => { diff --git a/src/data/list/pair.rs b/src/data/list/pair.rs index 4f1d027..524ffb3 100644 --- a/src/data/list/pair.rs +++ b/src/data/list/pair.rs @@ -1,11 +1,13 @@ //! [Single-pair list](https://en.wikipedia.org/wiki/Church_encoding#One_pair_as_a_list_node) +use alloc::vec::Vec; + use crate::combinators::{I, Z}; use crate::data::boolean::{fls, tru}; use crate::data::num::church::{is_zero, pred, succ, zero}; use crate::data::pair::{fst, pair, snd}; use crate::term::Term::*; -use crate::term::{abs, app, Term}; +use crate::term::{Term, abs, app}; /// Produces a `nil`, the last link of a pair-encoded list; equivalent to `boolean::fls`. /// diff --git a/src/data/list/parigot.rs b/src/data/list/parigot.rs index 5eb346d..0fa3282 100644 --- a/src/data/list/parigot.rs +++ b/src/data/list/parigot.rs @@ -2,7 +2,7 @@ use crate::data::boolean::{fls, tru}; use crate::term::Term::*; -use crate::term::{abs, app, Term, UD}; +use crate::term::{Term, UD, abs, app}; /// Produces a `nil`, the last link of a Parigot-encoded list; equivalent to `boolean::tru`. /// diff --git a/src/data/list/scott.rs b/src/data/list/scott.rs index b3d26b2..c26452b 100644 --- a/src/data/list/scott.rs +++ b/src/data/list/scott.rs @@ -2,7 +2,7 @@ use crate::data::boolean::{fls, tru}; use crate::term::Term::*; -use crate::term::{abs, app, Term, UD}; +use crate::term::{Term, UD, abs, app}; /// Produces a `nil`, the last link of a Scott-encoded list; equivalent to `boolean::tru`. /// diff --git a/src/data/num/binary.rs b/src/data/num/binary.rs index 7d58740..a816735 100644 --- a/src/data/num/binary.rs +++ b/src/data/num/binary.rs @@ -4,7 +4,7 @@ use crate::combinators::I; use crate::data::boolean::{fls, tru}; use crate::data::pair::{fst, pair, snd}; use crate::term::Term::*; -use crate::term::{abs, app, Term}; +use crate::term::{Term, abs, app}; /// A 0 bit; equivalent to `boolean::tru`. /// diff --git a/src/data/num/church.rs b/src/data/num/church.rs index 73aeea7..00a20e9 100644 --- a/src/data/num/church.rs +++ b/src/data/num/church.rs @@ -5,7 +5,7 @@ use crate::data::boolean::{and, fls, not, or, tru}; use crate::data::num::{parigot, scott, stumpfu}; use crate::data::pair::pair; use crate::term::Term::*; -use crate::term::{abs, app, Term}; +use crate::term::{Term, abs, app}; /// Produces a Church-encoded number zero; equivalent to `boolean::fls`. /// diff --git a/src/data/num/convert.rs b/src/data/num/convert.rs index 1ede018..1f76216 100644 --- a/src/data/num/convert.rs +++ b/src/data/num/convert.rs @@ -4,7 +4,7 @@ use self::Encoding::*; use crate::term::Term::*; -use crate::term::{abs, app, Term}; +use crate::term::{Term, abs, app}; /// The type of numeric encoding. #[derive(Debug, Clone, Copy)] diff --git a/src/data/num/parigot.rs b/src/data/num/parigot.rs index de1b5eb..a859465 100644 --- a/src/data/num/parigot.rs +++ b/src/data/num/parigot.rs @@ -2,7 +2,7 @@ use crate::data::boolean::{fls, tru}; use crate::term::Term::*; -use crate::term::{abs, app, Term}; +use crate::term::{Term, abs, app}; /// Produces a Parigot-encoded number zero; equivalent to `boolean::fls`. /// diff --git a/src/data/num/scott.rs b/src/data/num/scott.rs index d84d4bd..3072a74 100644 --- a/src/data/num/scott.rs +++ b/src/data/num/scott.rs @@ -3,7 +3,7 @@ use crate::combinators::Z; use crate::data::boolean::{fls, tru}; use crate::term::Term::*; -use crate::term::{abs, app, Term}; +use crate::term::{Term, abs, app}; /// Produces a Scott-encoded number zero; equivalent to `boolean::tru`. /// diff --git a/src/data/num/signed.rs b/src/data/num/signed.rs index 21245aa..3b10cb1 100644 --- a/src/data/num/signed.rs +++ b/src/data/num/signed.rs @@ -8,7 +8,7 @@ use crate::data::num::convert::Encoding::*; use crate::data::num::{church, parigot, scott, stumpfu}; use crate::data::pair::{fst, pair, snd, swap}; use crate::term::Term::*; -use crate::term::{abs, app, Term}; +use crate::term::{Term, abs, app}; /// Applied to a numeral with a specified encoding it produces a pair representing its signed /// equivalent. diff --git a/src/data/num/stumpfu.rs b/src/data/num/stumpfu.rs index 88b334e..3dfdf4e 100644 --- a/src/data/num/stumpfu.rs +++ b/src/data/num/stumpfu.rs @@ -4,7 +4,7 @@ use crate::data::boolean::{fls, tru}; use crate::data::num::convert::IntoChurchNum; use crate::data::num::{church, parigot, scott}; use crate::term::Term::*; -use crate::term::{abs, app, Term}; +use crate::term::{Term, abs, app}; /// Produces a Stump-Fu-encoded number zero; equivalent to `boolean::fls`. /// diff --git a/src/data/option.rs b/src/data/option.rs index ef23d44..42c82ae 100644 --- a/src/data/option.rs +++ b/src/data/option.rs @@ -3,7 +3,7 @@ use crate::combinators::I; use crate::data::boolean::{fls, tru}; use crate::term::Term::*; -use crate::term::{abs, app, Term}; +use crate::term::{Term, abs, app}; /// Produces a lambda-encoded empty option; equivalent to `boolean::tru`. /// diff --git a/src/data/pair.rs b/src/data/pair.rs index d64c539..7097c53 100644 --- a/src/data/pair.rs +++ b/src/data/pair.rs @@ -2,7 +2,7 @@ use crate::data::boolean::{fls, tru}; use crate::term::Term::*; -use crate::term::{abs, app, Term}; +use crate::term::{Term, abs, app}; /// Applied to two `Term`s it contains them in a lambda-encoded pair. /// diff --git a/src/data/result.rs b/src/data/result.rs index 1a9b401..bb621f6 100644 --- a/src/data/result.rs +++ b/src/data/result.rs @@ -4,7 +4,7 @@ use crate::combinators::I; use crate::data::boolean::{fls, tru}; use crate::data::option::{none, some}; use crate::term::Term::*; -use crate::term::{abs, app, Term}; +use crate::term::{Term, abs, app}; /// Applied to an argument it consumes it and produces a lambda-encoded `Result::Ok` that contains /// it. diff --git a/src/data/tuple.rs b/src/data/tuple.rs index f34a020..077e3fe 100644 --- a/src/data/tuple.rs +++ b/src/data/tuple.rs @@ -24,7 +24,7 @@ /// ``` #[macro_export] macro_rules! tuple { - ($first:expr, $($next:expr),+) => { + ($first:expr_2021, $($next:expr_2021),+) => { { let mut ret = app(Var(1), $first); $(ret = app(ret, $next);)* @@ -57,7 +57,7 @@ macro_rules! tuple { /// ``` #[macro_export] macro_rules! pi { - ($i:expr, $n:expr) => {{ + ($i:expr_2021, $n:expr_2021) => {{ let mut ret = Var($n + 1 - $i); for _ in 0..$n { diff --git a/src/lib.rs b/src/lib.rs index 803ab09..4b0c820 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,9 @@ //! **lambda_calculus** is a simple implementation of the untyped lambda calculus in Rust. - +#![no_std] #![deny(missing_docs)] #![deny(unsafe_code)] - +#[macro_use] +extern crate alloc; #[macro_use] pub mod term; pub mod combinators; @@ -10,11 +11,11 @@ pub mod parser; pub mod reduction; pub use self::parser::parse; -pub use self::reduction::beta; pub use self::reduction::Order::*; +pub use self::reduction::beta; pub use self::term::Notation::*; pub use self::term::Term::*; -pub use self::term::{abs, app, Term, UD}; +pub use self::term::{Term, UD, abs, app}; #[cfg(feature = "encoding")] pub mod data; diff --git a/src/parser.rs b/src/parser.rs index 2f916a0..a065a5f 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -6,10 +6,13 @@ use self::ParseError::*; use self::Token::*; pub use crate::term::Notation::*; use crate::term::Term::*; -use crate::term::{abs, app, Notation, Term}; -use std::collections::VecDeque; -use std::error::Error; -use std::fmt; +use crate::term::{Notation, Term, abs, app}; +use alloc::collections::VecDeque; +use alloc::string::String; +use alloc::string::ToString; +use alloc::vec::Vec; +use core::error::Error; +use core::fmt; /// An error returned by `parse()` when a parsing issue is encountered. #[derive(Debug, PartialEq, Eq)] @@ -231,7 +234,7 @@ fn _get_ast(tokens: &[Token], pos: &mut usize) -> Result /// Attempts to parse the input `&str` as a lambda `Term` encoded in the given `Notation`. /// /// - lambdas can be represented either with the greek letter (λ) or a backslash (\\ - -/// less aesthetic, but only one byte in size) +/// less aesthetic, but only one byte in size) /// - the identifiers in `Classic` notation are `String`s of alphabetic Unicode characters /// - `Classic` notation ignores whitespaces where unambiguous /// - the indices in the `DeBruijn` notation start with 1 and are hexadecimal digits diff --git a/src/reduction.rs b/src/reduction.rs index 9d8db14..e6fdf07 100644 --- a/src/reduction.rs +++ b/src/reduction.rs @@ -1,16 +1,18 @@ //! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s +use alloc::borrow::ToOwned; + pub use self::Order::*; use crate::term::Term::*; use crate::term::{Term, TermError}; -use std::{cmp, fmt, mem}; +use core::{cmp, fmt, mem}; /// The [evaluation order](http://www.cs.cornell.edu/courses/cs6110/2014sp/Handouts/Sestoft.pdf) of /// β-reductions. /// /// - the `NOR`, `HNO`, `APP` and `HAP` orders reduce expressions to their normal form /// - the `APP` order will fail to fully reduce expressions containing terms without a normal form, -/// e.g. the `Y` combinator (they will expand forever) +/// e.g. the `Y` combinator (they will expand forever) /// - the `CBN` order reduces to weak head normal form /// - the `CBV` order reduces to weak normal form /// - the `HSP` order reduces to head normal form @@ -92,7 +94,7 @@ impl Term { } _ => {} }, - Abs(ref mut abstracted) => abstracted._apply(rhs, depth + 1), + Abs(abstracted) => abstracted._apply(rhs, depth + 1), App(boxed) => { let (ref mut lhs_lhs, ref mut lhs_rhs) = **boxed; lhs_lhs._apply(rhs, depth); @@ -103,12 +105,12 @@ impl Term { fn update_free_variables(&mut self, added_depth: usize, own_depth: usize) { match self { - Var(ref mut i) => { + Var(i) => { if *i > own_depth { *i += added_depth } } - Abs(ref mut abstracted) => abstracted.update_free_variables(added_depth, own_depth + 1), + Abs(abstracted) => abstracted.update_free_variables(added_depth, own_depth + 1), App(boxed) => { let (ref mut lhs, ref mut rhs) = **boxed; lhs.update_free_variables(added_depth, own_depth); diff --git a/src/term.rs b/src/term.rs index 34467e7..3dedcd2 100644 --- a/src/term.rs +++ b/src/term.rs @@ -3,9 +3,13 @@ pub use self::Notation::*; pub use self::Term::*; use self::TermError::*; -use std::borrow::Cow; -use std::error::Error; -use std::fmt; +use alloc::borrow::Cow; +use alloc::borrow::ToOwned; +use alloc::boxed::Box; +use alloc::string::String; +use alloc::vec::Vec; +use core::error::Error; +use core::fmt; /// The character used to display lambda abstractions (a backslash). #[cfg(feature = "backslash_lambda")] @@ -386,7 +390,7 @@ impl Term { return false; } } - Abs(ref t) => stack.push((depth + 1, t)), + Abs(t) => stack.push((depth + 1, t)), App(boxed) => { let (ref f, ref a) = **boxed; stack.push((depth, f)); @@ -534,7 +538,7 @@ fn show_precedence_cla( }; base26_encode(ix) } - Abs(ref t) => { + Abs(t) => { let ret = { format!( "{}{}.{}", @@ -569,7 +573,7 @@ fn show_precedence_dbr(term: &Term, context_precedence: usize) -> String { Var(i) => { format!("{:X}", i) } - Abs(ref t) => { + Abs(t) => { let ret = format!("{}{:?}", LAMBDA, t); parenthesize_if(&ret, context_precedence > 1).into() } @@ -606,7 +610,7 @@ fn parenthesize_if(input: &str, condition: bool) -> Cow { /// ``` #[macro_export] macro_rules! app { - ($term1:expr, $($term2:expr),+) => { + ($term1:expr_2021, $($term2:expr_2021),+) => { { let mut term = $term1; $(term = app(term, $term2);)* @@ -628,7 +632,7 @@ macro_rules! app { /// ``` #[macro_export] macro_rules! abs { - ($n:expr, $term:expr) => {{ + ($n:expr_2021, $term:expr_2021) => {{ let mut term = $term; for _ in 0..$n { @@ -641,6 +645,8 @@ macro_rules! abs { #[cfg(test)] mod tests { + use alloc::string::ToString; + use super::*; #[test] @@ -690,7 +696,11 @@ mod tests { ); assert_eq!( - abs!(27, app!(Var(28), Var(29), Var(30), Var(50), Var(702), Var(703))).to_string(), + abs!( + 27, + app!(Var(28), Var(29), Var(30), Var(50), Var(702), Var(703)) + ) + .to_string(), "λa.λb.λc.λd.λe.λf.λg.λh.λi.λj.λk.λl.λm.λn.λo.λp.λq.λr.λs.λt.λu.λv.λw.λx.λy.λz.λaa.ab ac ad ax zz aaa" ); assert_eq!( @@ -769,11 +779,13 @@ mod tests { assert!(app(abs(Var(2)), abs(Var(1))).has_free_variables()); assert!(app(abs(Var(1)), abs(Var(2))).has_free_variables()); assert!(!app(abs(Var(1)), abs(Var(1))).has_free_variables()); - assert!(!(abs(app( - abs(app(Var(2), app(Var(1), Var(1)))), - abs(app(Var(2), app(Var(1), Var(1)))), - ))) - .has_free_variables()); + assert!( + !(abs(app( + abs(app(Var(2), app(Var(1), Var(1)))), + abs(app(Var(2), app(Var(1), Var(1)))), + ))) + .has_free_variables() + ); assert!((Var(0)).has_free_variables()); } } diff --git a/tests/lists.rs b/tests/lists.rs index c33ef89..3fa3299 100644 --- a/tests/lists.rs +++ b/tests/lists.rs @@ -6,7 +6,7 @@ use lambda::data::list::{church, parigot, scott}; use lambda::*; macro_rules! test_list { - ($name:ident, $function:ident, $($($n:expr),+ => $result:expr),+) => ( + ($name:ident, $function:ident, $($($n:expr_2021),+ => $result:expr_2021),+) => ( #[test] fn $name() { $( diff --git a/tests/num.rs b/tests/num.rs index 55f4978..79d1299 100644 --- a/tests/num.rs +++ b/tests/num.rs @@ -6,7 +6,7 @@ use lambda::data::num::{binary, church, parigot, scott, stumpfu}; use lambda::*; macro_rules! test_num { - ($encoding:ident, $name:ident, $conversion:ident, $function:ident, $($($n:expr),+ => $result:expr),+) => ( + ($encoding:ident, $name:ident, $conversion:ident, $function:ident, $($($n:expr_2021),+ => $result:expr_2021),+) => ( #[test] fn $name() { $(assert_eq!(beta(app!($encoding::$function(), $($n.$conversion()),*), HNO, 0), $result.$conversion());)* @@ -15,7 +15,7 @@ macro_rules! test_num { } macro_rules! test_num_all { - ($name:ident, $function:ident, $($($n:expr),+ => $result:expr),+) => ( + ($name:ident, $function:ident, $($($n:expr_2021),+ => $result:expr_2021),+) => ( #[test] fn $name() { $(assert_eq!(beta(app!(church::$function(), $($n.into_church()),*), HNO, 0), $result.into_church());)* diff --git a/tests/pair_list.rs b/tests/pair_list.rs index f2d8d6a..dd172ae 100644 --- a/tests/pair_list.rs +++ b/tests/pair_list.rs @@ -8,7 +8,7 @@ use lambda::data::num::church::is_zero; use lambda::*; macro_rules! vec_church { - ( $( $e:expr ),* ) => { + ( $( $e:expr_2021 ),* ) => { { let mut vec = Vec::new(); $( vec.push($e.into_church()); )* @@ -18,7 +18,7 @@ macro_rules! vec_church { } macro_rules! test_pair_list { - ($name:ident, $function:ident, $($($n:expr),+ => $result:expr),+) => ( + ($name:ident, $function:ident, $($($n:expr_2021),+ => $result:expr_2021),+) => ( #[test] fn $name() { $(assert_eq!( @@ -30,7 +30,7 @@ macro_rules! test_pair_list { } macro_rules! test_pair_list_lists_to_num { - ($name:ident, $function:ident, $($($n:expr),+ => $result:expr),+) => ( + ($name:ident, $function:ident, $($($n:expr_2021),+ => $result:expr_2021),+) => ( #[test] fn $name() { $(assert_eq!( @@ -42,7 +42,7 @@ macro_rules! test_pair_list_lists_to_num { } macro_rules! test_pair_list_all_lists { - ($name:ident, $function:ident, $($($n:expr),+ => $result:expr),+) => ( + ($name:ident, $function:ident, $($($n:expr_2021),+ => $result:expr_2021),+) => ( #[test] fn $name() { $(assert_eq!(