From 8e8bd9f2b141cab72726d6b70d6f5774f891fa53 Mon Sep 17 00:00:00 2001 From: Charles Johnson Date: Fri, 17 May 2024 09:50:35 +0900 Subject: [PATCH 1/5] Trying to define integer division but it takes so long to run --- zia-lang.org/crate/src/page/home/tutorials.rs | 110 +++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) diff --git a/zia-lang.org/crate/src/page/home/tutorials.rs b/zia-lang.org/crate/src/page/home/tutorials.rs index 9617fe9e..6ef904af 100644 --- a/zia-lang.org/crate/src/page/home/tutorials.rs +++ b/zia-lang.org/crate/src/page/home/tutorials.rs @@ -1,4 +1,4 @@ -pub const TUTORIALS: (Tutorial<18>, Tutorial<9>, Tutorial<12>) = ( +pub const TUTORIALS: (Tutorial<18>, Tutorial<9>, Tutorial<19>) = ( Tutorial { title: "Factorial", steps: [ @@ -246,6 +246,114 @@ pub const TUTORIALS: (Tutorial<18>, Tutorial<9>, Tutorial<12>) = ( expected_evaluation: "[ 5 , 3 , 1 ]", explanation: "We can now push to arrays with multiple elements" }, + TutorialStep { + command: "let (_x_ +1) > _x_", + #[cfg(test)] + expected_evaluation: "", + explanation: "The successor is always greater" + }, + TutorialStep { + command: "let 2 := 1 +1", + #[cfg(test)] + expected_evaluation: "", + explanation: "Let's define two to test this" + }, + TutorialStep { + command: "2 > 1", + #[cfg(test)] + expected_evaluation: "true", + explanation: "" + }, + TutorialStep { + command: "let _x_ - 0 -> _x_", + #[cfg(test)] + expected_evaluation: "", + explanation: "Define the base case for subtraction" + }, + TutorialStep { + command: "let (_x_ > _y_) => ((_x_ +1) - (_y_ +1) -> _x_ - _y_)", + #[cfg(test)] + expected_evaluation: "", + explanation: "This is how to simplify a subtraction expression" + }, + TutorialStep { + command: "2 - 1", + #[cfg(test)] + expected_evaluation: "1", + explanation: "" + }, + TutorialStep { + command: "let (_x_ > _y_) => (_x_ / _y_ -> ((_x_ - _y_) / _y_) +1)", + #[cfg(test)] + expected_evaluation: "", + explanation: "This is how to simplify a division expression" + }, + // TutorialStep { + // command: "let 3 := 2 +1", + // #[cfg(test)] + // expected_evaluation: "", + // explanation: "Define three to test" + // }, + // TutorialStep { + // command: "3 / 2", + // #[cfg(test)] + // expected_evaluation: "1", + // explanation: "Let's test evaluating an integer division expression" + // }, + // TutorialStep { + // command: "let _y_ / _y_ -> 1", + // #[cfg(test)] + // expected_evaluation: "", + // explanation: "A number divided by itself is always one" + // }, + // TutorialStep { + // command: "let (_y_ > _x_) => (_x_ / _y_ -> 0)", + // #[cfg(test)] + // expected_evaluation: "", + // explanation: "Integer by a larger number is zero" + // }, + // TutorialStep { + // command: "let _y_ % _y_ -> 0", + // #[cfg(test)] + // expected_evaluation: "", + // explanation: "There's no remainder when dividing something by itself" + // }, + // TutorialStep { + // command: "let (_x_ > _y_) => (_x_ % _y_ -> (_x_ - _y_) % _y_)", + // #[cfg(test)] + // expected_evaluation: "", + // explanation: "This is how to simplify a modulo expression" + // }, + // TutorialStep { + // command: "let (_y_ > _x_) => (_x_ % _y_ -> _x_)", + // #[cfg(test)] + // expected_evaluation: "", + // explanation: "This is how to simplify another modulo expression" + // }, + // TutorialStep { + // command: "let bits_of 0 -> [ 0 ]", + // #[cfg(test)] + // expected_evaluation: "", + // explanation: "Zero can be represented in binary as a single zero" + // }, + // TutorialStep { + // command: "let bits_of 1 -> [ 1 ]", + // #[cfg(test)] + // expected_evaluation: "", + // explanation: "One can be represented in binary as a single one" + // }, + // TutorialStep { + // command: "let (_x_ > 1) => (bits_of _x_ -> (bits_of (_x_ / 2)) push _x_ % 2)", + // #[cfg(test)] + // expected_evaluation: "", + // explanation: "Binary representations of larger numbers can be defined recursively using integer substraction and modulo" + // }, + // TutorialStep { + // command: "bits_of 2", + // #[cfg(test)] + // expected_evaluation: "[ 1 , 0 ]", + // explanation: "Two represented in binary is 10" + // }, ] } ); From 554959e3ceef439f0093d114d42d0200e6abd762 Mon Sep 17 00:00:00 2001 From: Charles Johnson Date: Sun, 2 Jun 2024 10:59:34 +0900 Subject: [PATCH 2/5] Set limit of 25 seconds for each tutorial step to complete --- zia-lang.org/crate/src/page/home/tutorials.rs | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/zia-lang.org/crate/src/page/home/tutorials.rs b/zia-lang.org/crate/src/page/home/tutorials.rs index 6ef904af..e972bda1 100644 --- a/zia-lang.org/crate/src/page/home/tutorials.rs +++ b/zia-lang.org/crate/src/page/home/tutorials.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +use std::time::{Instant, Duration}; + pub const TUTORIALS: (Tutorial<18>, Tutorial<9>, Tutorial<19>) = ( Tutorial { title: "Factorial", @@ -376,8 +379,25 @@ pub struct TutorialStep { expected_evaluation: &'static str, } +#[cfg(test)] +impl TutorialStep { + fn test(&self, context: &mut zia::multi_threaded::Context) { + let i = Instant::now(); + assert_eq!( + context.execute(self.command), + self.expected_evaluation, + "Failed at {0}", + self.command + ); + let time_taken = i.elapsed(); + let limit_in_seconds = 25; + assert!(time_taken < Duration::from_secs(limit_in_seconds), "{0} took longer than {limit_in_seconds} second - it took {time_taken:?}", self.command); + } +} + #[cfg(test)] mod test { + use zia::multi_threaded::NEW_CONTEXT; use super::TUTORIALS; @@ -386,36 +406,21 @@ mod test { fn factorial_tutorial() { let mut context = NEW_CONTEXT.clone(); for step in TUTORIALS.0.steps { - assert_eq!( - context.execute(step.command), - step.expected_evaluation, - "Failed at {0}", - step.command - ); + step.test(&mut context); } } #[test] fn relationships_tutorial() { let mut context = NEW_CONTEXT.clone(); for step in TUTORIALS.1.steps { - assert_eq!( - context.execute(step.command), - step.expected_evaluation, - "Failed at {0}", - step.command - ); + step.test(&mut context); } } #[test] fn array_tutorial() { let mut context = NEW_CONTEXT.clone(); for step in TUTORIALS.2.steps { - assert_eq!( - context.execute(step.command), - step.expected_evaluation, - "Failed at {0}", - step.command - ); + step.test(&mut context); } } } From 45706e41f01c47a4532fea3e62e3678e654af714 Mon Sep 17 00:00:00 2001 From: Charles Johnson Date: Sun, 2 Jun 2024 11:12:15 +0900 Subject: [PATCH 3/5] Resolve fmt issues --- zia-lang.org/crate/src/page/home/tutorials.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/zia-lang.org/crate/src/page/home/tutorials.rs b/zia-lang.org/crate/src/page/home/tutorials.rs index e972bda1..24758e67 100644 --- a/zia-lang.org/crate/src/page/home/tutorials.rs +++ b/zia-lang.org/crate/src/page/home/tutorials.rs @@ -1,5 +1,5 @@ #[cfg(test)] -use std::time::{Instant, Duration}; +use std::time::{Duration, Instant}; pub const TUTORIALS: (Tutorial<18>, Tutorial<9>, Tutorial<19>) = ( Tutorial { @@ -292,7 +292,7 @@ pub const TUTORIALS: (Tutorial<18>, Tutorial<9>, Tutorial<19>) = ( explanation: "This is how to simplify a division expression" }, // TutorialStep { - // command: "let 3 := 2 +1", + // command: "let 3 := 2 +1", // #[cfg(test)] // expected_evaluation: "", // explanation: "Define three to test" @@ -319,7 +319,7 @@ pub const TUTORIALS: (Tutorial<18>, Tutorial<9>, Tutorial<19>) = ( // command: "let _y_ % _y_ -> 0", // #[cfg(test)] // expected_evaluation: "", - // explanation: "There's no remainder when dividing something by itself" + // explanation: "There's no remainder when dividing something by itself" // }, // TutorialStep { // command: "let (_x_ > _y_) => (_x_ % _y_ -> (_x_ - _y_) % _y_)", @@ -390,7 +390,7 @@ impl TutorialStep { self.command ); let time_taken = i.elapsed(); - let limit_in_seconds = 25; + let limit_in_seconds = 25; assert!(time_taken < Duration::from_secs(limit_in_seconds), "{0} took longer than {limit_in_seconds} second - it took {time_taken:?}", self.command); } } From 29491c367d7574abb0bb2871d4831085e39efd02 Mon Sep 17 00:00:00 2001 From: Charles Johnson Date: Fri, 7 Jun 2024 00:22:55 +0900 Subject: [PATCH 4/5] Lazily compute examples of generalisations --- zia/src/context_search.rs | 233 +++++++++++++++++--------------------- 1 file changed, 102 insertions(+), 131 deletions(-) diff --git a/zia/src/context_search.rs b/zia/src/context_search.rs index f2a64284..044c73d0 100644 --- a/zia/src/context_search.rs +++ b/zia/src/context_search.rs @@ -36,9 +36,7 @@ use crate::{ use log::debug; use maplit::{hashmap, hashset}; use std::{ - collections::{HashMap, HashSet}, - fmt::Debug, - marker::PhantomData, + collections::{HashMap, HashSet}, fmt::Debug, iter, marker::PhantomData }; #[derive(Debug)] @@ -473,7 +471,7 @@ where let true_concept = self.snap_shot.read_concept(self.delta.as_ref(), true_id); let truths = true_concept.find_what_reduces_to_it(); - self.find_example(right, &truths.collect()).map( + self.find_example(right, truths).map( |substitutions| { // TODO: determine whether substitutions.example should be considered let true_syntax = self.to_ast(&true_id); @@ -494,9 +492,9 @@ where fn find_example( &self, generalisation: &SharedSyntax, - truths: &HashSet, + truths: impl Iterator, ) -> Option>> { - self.find_examples(generalisation, truths).pop() + self.find_examples(generalisation.clone(), truths).next() } pub fn find_examples_of_inferred_reduction( @@ -556,11 +554,14 @@ where let true_id = spawned_context_search .concrete_concept_id(ConcreteConceptType::True) .expect("true concept must exist"); - let truths = self.equivalent_concepts_to(&true_id); + let equivalent_concept = + self.snap_shot.read_concept(self.delta.as_ref(), true_id); + // TODO handle case when a concept implicitly reduces to `equivalent_concept` + let truths = equivalent_concept.find_what_reduces_to_it().chain(iter::once(true_id)); + let irp = implication_rule_pattern.share(); - spawned_context_search - .find_examples(&irp, &truths) - .into_iter() + let result = spawned_context_search + .find_examples(irp, truths) .find_map(|substitutions| { substitutions .generalisation @@ -600,68 +601,67 @@ where ) }) }) - }) + }); + result } - // TODO Lazily compute the concepts that are equivalent to a given normal form - // until a required number of examples are found - // `generalisation` needs to contain bound variables - fn find_examples( - &self, - generalisation: &SharedSyntax, - equivalence_set: &HashSet, /* All concepts that are equal to generalisation */ - ) -> Vec>> { + fn find_examples<'a>( + &'a self, + generalisation: SharedSyntax, + equivalence_set: impl Iterator + 'a, /* All concepts that are equal to generalisation */ + ) -> impl Iterator>> + 'a { + let iterator: Box>>>; if let Some((left, right)) = generalisation.get_expansion() { - self.find_examples_of_branched_generalisation( - &left, - &right, + iterator = Box::new(self.find_examples_of_branched_generalisation( + left, + right, equivalence_set, - ) + )); } else { debug_assert!( - self.contains_bound_variable_syntax(generalisation), + self.contains_bound_variable_syntax(&generalisation), "Generalisation ({generalisation}) doesn't contain bound variables" ); - equivalence_set - .iter() - .map(|c| { - let example = self.to_ast(c); + iterator = Box::new(equivalence_set + .map(move |c| { + let example = self.to_ast(&c); ExampleSubstitutions { generalisation: hashmap! {generalisation.clone() => example}, example: hashmap!{} } - }) - .collect() + })); } + iterator } - fn find_examples_of_branched_generalisation( - &self, - left: &SharedSyntax, - right: &SharedSyntax, - equivalence_set: &HashSet, - ) -> Vec>> { + fn find_examples_of_branched_generalisation<'a>( + &'a self, + left: SharedSyntax, + right: SharedSyntax, + equivalence_set: impl Iterator + 'a, + ) -> impl Iterator>> + 'a { + let iterator: Box>>>; match ( - self.contains_bound_variable_syntax(left), - self.contains_bound_variable_syntax(right), + self.contains_bound_variable_syntax(&left), + self.contains_bound_variable_syntax(&right), ) { (true, true) => { - equivalence_set - .iter() + iterator = Box::new(equivalence_set .filter_map(|equivalent_concept_id| { - self.composition_of_concept(equivalent_concept_id) + self.composition_of_concept(&equivalent_concept_id) }) - .flat_map(|(equivalent_left_id, equivalent_right_id)| { - let equivalent_left_equivalence_set = - self.equivalent_concepts_to(&equivalent_left_id); - let equivalent_right_equivalence_set = - self.equivalent_concepts_to(&equivalent_right_id); - self.find_examples( - left, - &equivalent_left_equivalence_set, + .filter_map(move |(equivalent_left_id, equivalent_right_id)| { + let equivalent_concept = + self.snap_shot.read_concept(self.delta.as_ref(), equivalent_left_id); + // TODO handle case when a concept implicitly reduces to `equivalent_concept` + let equivalent_left_equivalence_set = equivalent_concept.find_what_reduces_to_it().chain(iter::once(equivalent_left_id)); + + let maybe_example = self.find_examples( + left.clone(), + equivalent_left_equivalence_set, ) - .into_iter() - .flat_map(|left_example| { + // TODO try to find a case where this needs to be a flat_map method call + .find_map(|left_example| { let mut right_clone = right.clone(); let mutable_right = Syntax::::make_mut(&mut right_clone); @@ -675,121 +675,106 @@ where &right_clone, &left_example.example, ); + let equivalent_concept = + self.snap_shot.read_concept(self.delta.as_ref(), equivalent_right_id); + // TODO handle case when a concept implicitly reduces to `equivalent_concept` + let mut equivalent_right_equivalence_set = equivalent_concept.find_what_reduces_to_it().chain(iter::once(equivalent_right_id)); if self.contains_bound_variable_syntax( &substituted_right, ) { self.find_examples( - &substituted_right, - &equivalent_right_equivalence_set, + substituted_right, + equivalent_right_equivalence_set, ) - .into_iter() - .filter_map(|right_example| { + // TODO find test case where this needs to be filter_map + .find_map(|right_example| { right_example .consistent_merge(left_example.clone()) }) - .collect::>() } else if self .recursively_reduce(&substituted_right) .0 .get_concept() .map_or(false, |id| { - equivalent_right_equivalence_set - .contains(&id) + equivalent_right_equivalence_set.any(|equivalent_right_id| equivalent_right_id == id) }) { - vec![left_example] + Some(left_example) } else { - vec![] + None } - }) - .collect::>() - }) - .collect() + }); + maybe_example + })); }, - (true, false) => self.find_examples_of_half_generalisation( - left, - right, + (true, false) => {iterator = Box::new(self.find_examples_of_half_generalisation( + left.clone(), + right.clone(), equivalence_set, Hand::Right, - ), - (false, true) => self.find_examples_of_half_generalisation( - right, - left, + ).into_iter());}, + (false, true) => { + iterator = Box::new(self.find_examples_of_half_generalisation( + right.clone(), + left.clone(), equivalence_set, Hand::Left, - ), - (false, false) => vec![], + ).into_iter());}, + (false, false) => {iterator = Box::new(iter::empty())}, } + iterator } - fn find_examples_of_half_generalisation( - &self, - generalised_part: &SharedSyntax, - non_generalised_part: &SharedSyntax, - equivalence_set_of_composition: &HashSet, + fn find_examples_of_half_generalisation<'a>( + &'a self, + generalised_part: SharedSyntax, + non_generalised_part: SharedSyntax, + mut equivalence_set_of_composition: impl Iterator + 'a, non_generalised_hand: Hand, - ) -> Vec>> { - let mut subs = Vec::new(); - subs.extend(equivalence_set_of_composition.iter().find_map(|equivalent_concept_id| { + ) -> Option>> { + let non_generalised_part_clone = non_generalised_part.clone(); + let generalised_part_clone = generalised_part; + // TODO try to test if this needs to be a flat_map call + equivalence_set_of_composition.find_map(move |equivalent_concept_id| { let equivalent_concept = self .snap_shot - .read_concept(self.delta.as_ref(), *equivalent_concept_id); + .read_concept(self.delta.as_ref(), equivalent_concept_id); let (left, right) = equivalent_concept.get_composition()?; let (equivalent_non_generalised_hand, equivalent_generalised_hand) = match non_generalised_hand { Hand::Left => (left, right), Hand::Right => (right, left) }; - if Some(equivalent_non_generalised_hand) != non_generalised_part.get_concept() { + if Some(equivalent_non_generalised_hand) != non_generalised_part_clone.get_concept() { if self.snap_shot.read_concept(self.delta.as_ref(), equivalent_non_generalised_hand).free_variable() { - return self.find_example(generalised_part, &hashset!{equivalent_generalised_hand}).and_then(|subs| { + return self.find_example(&generalised_part_clone, iter::once(equivalent_generalised_hand)).and_then(|subs| { // Could have a more efficient method for this - subs.consistent_merge(ExampleSubstitutions{example: hashmap!{equivalent_non_generalised_hand => non_generalised_part.clone()}, ..Default::default()}) + subs.consistent_merge(ExampleSubstitutions{example: hashmap!{equivalent_non_generalised_hand => non_generalised_part_clone.clone()}, ..Default::default()}) }) } return None; } - self.find_example(generalised_part, &hashset!{equivalent_generalised_hand}) - })); - - let Some(non_generalised_id) = non_generalised_part.get_concept() - else { - return subs; - }; - let non_generalised_concept = self - .snap_shot - .read_concept(self.delta.as_ref(), non_generalised_id); - let examples = - non_generalised_concept.iter_hand_of(non_generalised_hand); - subs.extend( - examples - .flat_map(|(example_hand, composition)| { - let mut generalised_hands_and_substitutions = vec![]; - if equivalence_set_of_composition.contains(&composition) { - generalised_hands_and_substitutions.push(example_hand); - } - generalised_hands_and_substitutions - }) - .filter_map(|example_hand| { + self.find_example(&generalised_part_clone, iter::once(equivalent_generalised_hand)).or_else(|| { + let non_generalised_id = non_generalised_part.get_concept()?; + let example_hand = match non_generalised_hand { + Hand::Left => (left == non_generalised_id).then_some(right)?, + Hand::Right => (right == non_generalised_id).then_some(left)?, + }; let example_hand_syntax = self.to_ast(&example_hand); Syntax::::check_example( &example_hand_syntax, - generalised_part, + &generalised_part_clone, ) .or_else(|| { // TODO handle case when a concept implicitly reduces to `non_generalised_hand` - let mut equivalence_set = hashset! {example_hand}; + let equivalence_set = iter::once(example_hand); let non_generalised_hand_concept = self .snap_shot .read_concept(self.delta.as_ref(), example_hand); - equivalence_set.extend( - non_generalised_hand_concept - .find_what_reduces_to_it(), - ); - self.find_example(generalised_part, &equivalence_set) + self.find_example(&generalised_part_clone, equivalence_set.chain(non_generalised_hand_concept + .find_what_reduces_to_it())) }) - }), - ); - subs + }) + }) } // Reduces a syntax tree based on the properties of the left branch and the branches of the right branch @@ -1177,20 +1162,6 @@ where self.composition_of_concept(l).is_none() } - // TODO: move to separate struct that just has self.delta and self.snap_shot - fn equivalent_concepts_to( - &self, - equivalent_id: &S::ConceptId, - ) -> HashSet { - let equivalent_concept = - self.snap_shot.read_concept(self.delta.as_ref(), *equivalent_id); - // TODO handle case when a concept implicitly reduces to `equivalent_concept` - let mut equivalence_set: HashSet = - equivalent_concept.find_what_reduces_to_it().collect(); - equivalence_set.insert(*equivalent_id); - equivalence_set - } - // TODO: move to separate struct that just has self.delta and self.snap_shot fn composition_of_concept( &self, From 99844c47c3e0acc47cbb68ccba5a8f5a80895441 Mon Sep 17 00:00:00 2001 From: Charle Johnson Date: Fri, 10 Oct 2025 18:38:31 +0000 Subject: [PATCH 5/5] Uncomment out tutorial steps --- zia-lang.org/crate/src/page/home/tutorials.rs | 134 +++++++++--------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/zia-lang.org/crate/src/page/home/tutorials.rs b/zia-lang.org/crate/src/page/home/tutorials.rs index d62aa07b..1a82a13c 100644 --- a/zia-lang.org/crate/src/page/home/tutorials.rs +++ b/zia-lang.org/crate/src/page/home/tutorials.rs @@ -1,7 +1,7 @@ #[cfg(test)] use std::time::{Duration, Instant}; -pub const TUTORIALS: (Tutorial<18>, Tutorial<9>, Tutorial<19>) = ( +pub const TUTORIALS: (Tutorial<18>, Tutorial<9>, Tutorial<30>) = ( Tutorial { title: "Factorial", steps: [ @@ -291,72 +291,72 @@ pub const TUTORIALS: (Tutorial<18>, Tutorial<9>, Tutorial<19>) = ( expected_evaluation: "", explanation: "This is how to simplify a division expression" }, - // TutorialStep { - // command: "let 3 := 2 +1", - // #[cfg(test)] - // expected_evaluation: "", - // explanation: "Define three to test" - // }, - // TutorialStep { - // command: "3 / 2", - // #[cfg(test)] - // expected_evaluation: "1", - // explanation: "Let's test evaluating an integer division expression" - // }, - // TutorialStep { - // command: "let _y_ / _y_ -> 1", - // #[cfg(test)] - // expected_evaluation: "", - // explanation: "A number divided by itself is always one" - // }, - // TutorialStep { - // command: "let (_y_ > _x_) => (_x_ / _y_ -> 0)", - // #[cfg(test)] - // expected_evaluation: "", - // explanation: "Integer by a larger number is zero" - // }, - // TutorialStep { - // command: "let _y_ % _y_ -> 0", - // #[cfg(test)] - // expected_evaluation: "", - // explanation: "There's no remainder when dividing something by itself" - // }, - // TutorialStep { - // command: "let (_x_ > _y_) => (_x_ % _y_ -> (_x_ - _y_) % _y_)", - // #[cfg(test)] - // expected_evaluation: "", - // explanation: "This is how to simplify a modulo expression" - // }, - // TutorialStep { - // command: "let (_y_ > _x_) => (_x_ % _y_ -> _x_)", - // #[cfg(test)] - // expected_evaluation: "", - // explanation: "This is how to simplify another modulo expression" - // }, - // TutorialStep { - // command: "let bits_of 0 -> [ 0 ]", - // #[cfg(test)] - // expected_evaluation: "", - // explanation: "Zero can be represented in binary as a single zero" - // }, - // TutorialStep { - // command: "let bits_of 1 -> [ 1 ]", - // #[cfg(test)] - // expected_evaluation: "", - // explanation: "One can be represented in binary as a single one" - // }, - // TutorialStep { - // command: "let (_x_ > 1) => (bits_of _x_ -> (bits_of (_x_ / 2)) push _x_ % 2)", - // #[cfg(test)] - // expected_evaluation: "", - // explanation: "Binary representations of larger numbers can be defined recursively using integer substraction and modulo" - // }, - // TutorialStep { - // command: "bits_of 2", - // #[cfg(test)] - // expected_evaluation: "[ 1 , 0 ]", - // explanation: "Two represented in binary is 10" - // }, + TutorialStep { + command: "let 3 := 2 +1", + #[cfg(test)] + expected_evaluation: "", + explanation: "Define three to test" + }, + TutorialStep { + command: "3 / 2", + #[cfg(test)] + expected_evaluation: "1", + explanation: "Let's test evaluating an integer division expression" + }, + TutorialStep { + command: "let _y_ / _y_ -> 1", + #[cfg(test)] + expected_evaluation: "", + explanation: "A number divided by itself is always one" + }, + TutorialStep { + command: "let (_y_ > _x_) => (_x_ / _y_ -> 0)", + #[cfg(test)] + expected_evaluation: "", + explanation: "Integer by a larger number is zero" + }, + TutorialStep { + command: "let _y_ % _y_ -> 0", + #[cfg(test)] + expected_evaluation: "", + explanation: "There's no remainder when dividing something by itself" + }, + TutorialStep { + command: "let (_x_ > _y_) => (_x_ % _y_ -> (_x_ - _y_) % _y_)", + #[cfg(test)] + expected_evaluation: "", + explanation: "This is how to simplify a modulo expression" + }, + TutorialStep { + command: "let (_y_ > _x_) => (_x_ % _y_ -> _x_)", + #[cfg(test)] + expected_evaluation: "", + explanation: "This is how to simplify another modulo expression" + }, + TutorialStep { + command: "let bits_of 0 -> [ 0 ]", + #[cfg(test)] + expected_evaluation: "", + explanation: "Zero can be represented in binary as a single zero" + }, + TutorialStep { + command: "let bits_of 1 -> [ 1 ]", + #[cfg(test)] + expected_evaluation: "", + explanation: "One can be represented in binary as a single one" + }, + TutorialStep { + command: "let (_x_ > 1) => (bits_of _x_ -> (bits_of (_x_ / 2)) push _x_ % 2)", + #[cfg(test)] + expected_evaluation: "", + explanation: "Binary representations of larger numbers can be defined recursively using integer substraction and modulo" + }, + TutorialStep { + command: "bits_of 2", + #[cfg(test)] + expected_evaluation: "[ 1 , 0 ]", + explanation: "Two represented in binary is 10" + }, ] } );