diff --git a/src/assignments/assignment08/church.rs b/src/assignments/assignment08/church.rs new file mode 100644 index 0000000..251fda4 --- /dev/null +++ b/src/assignments/assignment08/church.rs @@ -0,0 +1,71 @@ +//! Church Numerals +//! +//! This exercise involves the use of "Church numerals", a +//! representation of natural numbers using lambda calculus, named after +//! Alonzo Church. Each Church numeral corresponds to a natural number `n` +//! and is represented as a higher-order function that applies a given function `f` `n` times. +//! +//! For more information, see: +//! - +//! - + +use std::rc::Rc; + +/// Church numerals are represented as higher-order functions that take a function `f` +pub type Church = Rc T>) -> Rc T>>; + +/// This function returns a Church numeral equivalent of the natural number 1. +/// It takes a function `f` and applies it exactly once. +pub fn one() -> Church { + Rc::new(move |f| Rc::new(move |x| f(x))) +} + +/// This function returns a Church numeral equivalent of the natural number 2. +/// It takes a function `f` and applies it twice. +pub fn two() -> Church { + Rc::new(move |f| Rc::new(move |x| f(f(x)))) +} + +/// This function represents the Church numeral for zero. As zero applications +/// of `f` should leave the argument unchanged, the function simply returns the input. +pub fn zero() -> Church { + Rc::new(|_| Rc::new(|x| x)) +} + +/// Implement a function to add 1 to a given Church numeral. +pub fn succ(n: Church) -> Church { + todo!() +} + +/// Implement a function to add two Church numerals. +pub fn add(n: Church, m: Church) -> Church { + todo!() +} + +/// Implement a function to multiply (mult) two Church numerals. +pub fn mult(n: Church, m: Church) -> Church { + todo!() +} + +/// Implement a function to raise one Church numeral to the power of another. +/// This is the Church numeral equivalent of the natural number operation of exponentiation. +/// Given two natural numbers `n` and `m`, the function should return a Church numeral +/// that represents `n` to the power of `m`. The key is to convert `n` and `m` to Church numerals, +/// and then apply the Church numeral for `m` (the exponent) to the Church numeral for `n` (the base). +/// Note: This function should be implemented *WITHOUT* using the `to_usize` or any `pow`-like method. +pub fn exp(n: usize, m: usize) -> Church { + // ACTION ITEM: Uncomment the following lines and replace `todo!()` with your code. + // let n = from_usize(n); + // let m = from_usize(m); + todo!() +} + +/// Implement a function to convert a Church numeral to a usize type. +pub fn to_usize(n: Church) -> usize { + todo!() +} + +/// Implement a function to convert a usize type to a Church numeral. +pub fn from_usize(n: usize) -> Church { + todo!() +} diff --git a/src/assignments/assignment08/church_grade.rs b/src/assignments/assignment08/church_grade.rs new file mode 100644 index 0000000..1df5db4 --- /dev/null +++ b/src/assignments/assignment08/church_grade.rs @@ -0,0 +1,73 @@ +#[cfg(test)] +mod test { + use rand::Rng; + + use crate::assignments::assignment08::church::*; + + #[test] + fn you_must_pass_these_examples() { + let c_zero = zero::(); + assert_eq!(to_usize(c_zero.clone()), 0); + + let c_one = succ(c_zero.clone()); + assert_eq!(to_usize(c_one.clone()), to_usize(one::<()>())); + + let c_two = add(c_one.clone(), c_one.clone()); + let c_three = add(c_one.clone(), c_two.clone()); + assert_eq!(to_usize(c_three.clone()), 3); + + let c_product = mult(c_three.clone(), c_two.clone()); + assert_eq!(to_usize(c_product.clone()), 6); + + let c_exponent = exp::<()>(6, 3); + assert_eq!(to_usize(c_exponent), 216); + + let c_exponent2 = exp::<()>(3, 0); + assert_eq!(to_usize(c_exponent2), 1); + } + + fn id(n: usize) -> usize { + to_usize(from_usize::<()>(n)) + } + + fn c_id(n: Church) -> Church { + from_usize(to_usize(n)) + } + + #[test] + fn engineering_isnt_just_mathematics() { + const N: usize = 77777; + assert_eq!(N, id(N)); + } + + /// This test case is an optional challenge. + /// While it's not necessary to pass this test, + /// successfully doing so could provide a sense of satisfaction and achievement. + // #[test] + // fn i_said_engineering_isnt_just_mathematics() { + // const N: usize = 777777777777777; + // assert_eq!(N, id(N)); + // } + + #[test] + fn be_honest() { + let mut rng = rand::thread_rng(); + + for _ in 0..77 { + let x = rng.gen_range(0..=7); + let y = rng.gen_range(0..=7); + + let c_x = from_usize(x); + let c_y = from_usize(y); + + let c_sum = add(c_x.clone(), c_y.clone()); + assert_eq!(to_usize(c_id(c_sum)), x + y); + + let c_prod = mult(c_x.clone(), c_y.clone()); + assert_eq!(to_usize(c_id(c_prod)), x * y); + + let c_exp = exp(x, y); + assert_eq!(to_usize(c_id(c_exp)), x.pow(y as u32)); + } + } +} diff --git a/src/assignments/assignment08/mod.rs b/src/assignments/assignment08/mod.rs index c601b9a..a63077f 100644 --- a/src/assignments/assignment08/mod.rs +++ b/src/assignments/assignment08/mod.rs @@ -5,7 +5,10 @@ //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-08.sh` works fine. //! See `assignment08/*_grade.rs` and `/scripts/grade-08.sh` for the test script. +pub mod church; pub mod small_exercises; + +mod church_grade; mod small_exercises_grade; // TODO: add kyeongmin's church encoding asignment