diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ff24326..77fb688 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -31,7 +31,7 @@ jobs: uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: 1.70.0 + toolchain: 1.75.0 override: true - name: Build run: cargo build --verbose diff --git a/canrun/Cargo.toml b/canrun/Cargo.toml index 9145c85..8c963df 100644 --- a/canrun/Cargo.toml +++ b/canrun/Cargo.toml @@ -10,7 +10,7 @@ categories = ["algorithms", "mathematics"] keywords = ["logic", "dsl", "kanren"] license = "MIT/Apache-2.0" edition = "2021" -rust-version = "1.70.0" +rust-version = "1.75.0" [dependencies] im-rc = "15.1.0" diff --git a/canrun/src/core/query.rs b/canrun/src/core/query.rs index f3425b2..7c1b074 100644 --- a/canrun/src/core/query.rs +++ b/canrun/src/core/query.rs @@ -24,7 +24,7 @@ A blanket impl covers anything that implements [`StateIterator`], so many types including [`Goal`](crate::goals) and [`State`](crate::State) are queryable. */ -pub trait Query<'a> { +pub trait Query { /** Get [reified](crate::core::Reify) results from things that can produce [`StateIter`](crate::core::StateIter)s. @@ -57,11 +57,11 @@ pub trait Query<'a> { assert_eq!(result, vec![1]) ``` */ - fn query(self, query: Q) -> Box + 'a>; + fn query(self, query: Q) -> impl Iterator; } -impl<'a, S: StateIterator + 'a> Query<'a> for S { - fn query(self, query: Q) -> Box + 'a> { +impl Query for S { + fn query(self, query: Q) -> impl Iterator { Box::new( self.into_states() .filter_map(move |s| query.reify_in(&s.ready()?)), diff --git a/canrun/src/goals/both.rs b/canrun/src/goals/both.rs index ad7ba72..8e8f5be 100644 --- a/canrun/src/goals/both.rs +++ b/canrun/src/goals/both.rs @@ -5,9 +5,9 @@ use crate::core::State; A [Goal](crate::goals::Goal) that only succeeds if both sub-goals succeed. Create with [`both`]. */ #[derive(Debug)] -pub struct Both { - a: Box, - b: Box, +pub struct Both { + a: A, + b: B, } /** @@ -41,14 +41,11 @@ let result: Vec<_> = goal.query(x).collect(); assert_eq!(result, vec![]) // Empty result ``` */ -pub fn both(a: impl Goal, b: impl Goal) -> Both { - Both { - a: Box::new(a), - b: Box::new(b), - } +pub fn both(a: A, b: B) -> Both { + Both { a, b } } -impl Goal for Both { +impl Goal for Both { fn apply(&self, state: State) -> Option { self.a.apply(state).and_then(|s| self.b.apply(s)) } diff --git a/canrun/src/goals/lazy.rs b/canrun/src/goals/lazy.rs index c2d735c..6b21fb3 100644 --- a/canrun/src/goals/lazy.rs +++ b/canrun/src/goals/lazy.rs @@ -5,20 +5,18 @@ use crate::core::State; use super::Goal; -type LazyFun = dyn Fn() -> Box; - /** A [Goal](crate::goals::Goal) that is generated via callback just as it is about to be evaluated. Create with [`lazy`]. */ -pub struct Lazy { - fun: Rc, +pub struct Lazy { + fun: Rc G>, } -impl Debug for Lazy { +impl Debug for Lazy { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Lazy") - .field("fun", &"Rc Box>") + .field("fun", &"Rc impl Goal>") .finish() } } @@ -44,14 +42,15 @@ let result: Vec<_> = goal.query(x).collect(); assert_eq!(result, vec![1]) ``` */ -pub fn lazy(fun: F) -> Lazy +pub fn lazy(fun: F) -> Lazy where - F: (Fn() -> Box) + 'static, + G: Goal, + F: (Fn() -> G) + 'static, { Lazy { fun: Rc::new(fun) } } -impl Goal for Lazy { +impl Goal for Lazy { fn apply(&self, state: State) -> Option { let fun = &self.fun; let goal = fun(); diff --git a/canrun/src/goals/mod.rs b/canrun/src/goals/mod.rs index 097d82d..311711b 100644 --- a/canrun/src/goals/mod.rs +++ b/canrun/src/goals/mod.rs @@ -82,3 +82,15 @@ impl Goal for Rc { self.as_ref().apply(state) } } + +impl Goal for Rc { + fn apply(&self, state: State) -> Option { + self.as_ref().apply(state) + } +} + +impl Goal for Box { + fn apply(&self, state: State) -> Option { + self.as_ref().apply(state) + } +} diff --git a/canrun/src/goals/not.rs b/canrun/src/goals/not.rs index 47cc2de..8ae8ca1 100644 --- a/canrun/src/goals/not.rs +++ b/canrun/src/goals/not.rs @@ -12,11 +12,11 @@ A [Goal](crate::goals::Goal) that only succeeds if the sub-goal is proved to alw See [`not()`] for more details. */ #[derive(Debug)] -pub enum Not { +pub enum Not { /// A `Not` with a sub-goal that failed quickly at creation time Fail, /// A `Not` goal that needs further evaluation to see if it will succeed. - Maybe(Rc), + Maybe(Rc>), } /** @@ -61,7 +61,7 @@ is able to conclusively prove or disprove the sub-goal. All of this is not to discourage usage, but just to say that you should try to keep them relatively simple and as precise as possible. */ -pub fn not(goal: impl Goal) -> Not { +pub fn not(goal: G) -> Not { // We run the subgoal in isolation right up front for two reasons... let mut inner_states = goal.apply(State::new()).into_states().peekable(); if inner_states.peek().is_none() { @@ -81,7 +81,7 @@ pub fn not(goal: impl Goal) -> Not { } } -impl Goal for Not { +impl Goal for Not { fn apply(&self, state: State) -> Option { match self { Not::Fail => Some(state), @@ -96,10 +96,11 @@ impl Goal for Not { } } -/** A [`Not`] goal that needs to keep evaluating the state as variables are resolved. */ +/** A [`Not`] goal that needs to keep evaluating the state as variables are + * resolved. */ #[derive(Debug)] -pub struct NotConstraint { - goal: Rc, +pub struct NotConstraint { + goal: Rc, vars: LVarList, } @@ -107,7 +108,7 @@ fn any_succeed(state: Option) -> bool { state.into_states().next().is_some() } -impl Constraint for NotConstraint { +impl Constraint for NotConstraint { fn attempt(&self, state: &State) -> Result { // If the internal goal succeeded... if any_succeed(self.goal.apply(state.clone())) { diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 08bcbb5..03068bd 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/tgecho/canrun_rs" documentation = "https://docs.rs/crate/canrun_collections" license = "MIT/Apache-2.0" edition = "2021" -rust-version = "1.70.0" +rust-version = "1.75.0" [dependencies] canrun = { path = "../canrun"}