mod list_size { use mononym::*; // Emulates the following dependent pair in Idris: // (t: Type) -> (list: Vec t) -> (size: usize ** ListHasSize size list) exists! { ExistSize(size: usize) => ListHasSize(list: Vec); } pub fn list_size>>( seed: Seed, list: &Named>, ) -> ExistSize, T, ListVal> { let size = list.value().len(); new_exist_size(seed, size) } } mod list_positive { use mononym::*; exists! { ExistPositives(count: usize) => ListHasPositives(list: Vec); } pub fn count_positive_integers>>( seed: Seed, list: &Named>, ) -> ExistPositives, ListVal> { let count = list.value().iter().filter(|x| **x > 0).count(); new_exist_positives(seed, count) } } mod greater_half { use mononym::*; proof! { GreaterThanHalf(numerator: usize, denominator: usize); } pub fn greater_than_half< NumeratorVal: HasType, DenominatorVal: HasType, >( x: &Named, y: &Named, ) -> Option> { if *x.value() * 2 > *y.value() { Some(GreaterThanHalf::new()) } else { None } } } mod greater_than_half_positive { use mononym::*; use super::{ greater_half::GreaterThanHalf, list_positive::ListHasPositives, list_size::ListHasSize, }; proof! { GreaterThanHalfPositive(list: Vec); } pub fn greater_than_half_positive< ListVal: HasType>, TotalCountVal: HasType, PositiveCountVal: HasType, >( _has_size: &ListHasSize, _has_positives: &ListHasPositives, _greater_than_half: &GreaterThanHalf, ) -> GreaterThanHalfPositive { GreaterThanHalfPositive::new() } } mod greater_than_half_positive_dynamic { use mononym::*; use super::{ greater_half::greater_than_half, greater_than_half_positive::{ greater_than_half_positive, GreaterThanHalfPositive, }, list_positive::count_positive_integers, list_size::list_size, }; pub fn maybe_greater_than_half_positive>>( seed: Seed, data: &Named>, ) -> Option> { let (seed1, seed2) = seed.replicate(); let size = list_size(seed1, &data); let positives = count_positive_integers(seed2, &data); let greater_half = greater_than_half(&positives.count, &size.size); let proof = greater_half.map(|greater_half| { greater_than_half_positive( &size.list_has_size, &positives.list_has_positives, &greater_half, ) }); proof } } mod process_static { use mononym::*; use super::greater_than_half_positive::GreaterThanHalfPositive; pub fn process_data>>( _: &Named>, _greater_than_half_positive: &GreaterThanHalfPositive, ) -> i64 { 0 } } mod process_data_dynamic { use mononym::with_seed; use super::{ greater_than_half_positive_dynamic::maybe_greater_than_half_positive, process_static::process_data as process_data_static, }; #[derive(Debug, Eq, PartialEq)] pub enum Error { LessThanHalfPositive, } pub fn process_data(data: Vec) -> Result { with_seed(move |seed| { let (seed1, seed2) = seed.replicate(); let data = seed1.new_named(data); let proof = maybe_greater_than_half_positive(seed2, &data) .ok_or_else(|| Error::LessThanHalfPositive)?; let res = process_data_static(&data, &proof); Ok(res) }) } } fn main() { use self::process_data_dynamic::{ process_data, Error, }; let data = vec![3, 2, 1, 0, -1]; process_data(data).unwrap(); let data = vec![3, 2, 1, 0, -1, -2]; let res = process_data(data); assert_eq!(res, Err(Error::LessThanHalfPositive)); }