canrun 0.2.0

A logic programming library inspired by the *Kanren family of language DSLs.
Documentation
//! Make declarative assertions about the relationships between values.
//!
//! [`Goals`](crate::goals) provide a high level interface for defining logic
//! programs. They are composable, with many higher level goals being made
//! up of lower level primitives. Since the typical way of using goals are
//! through simple functions, it is easy to build and reuse custom, first class
//! goal constructors.
//!
//! While [`State`] exposes a lower level API, in practice there really
//! shouldn't be anything that can't be expressed using goals.
use crate::domains::Domain;
use crate::state::{Constraint, Fork, State};
use crate::state::{IterResolved, ResolvedStateIter};
use crate::Query;
use crate::ReifyIn;
use std::rc::Rc;

mod all;
mod any;
mod both;
pub mod cmp;
mod custom;
mod either;
mod lazy;
pub mod ops;
pub mod project;
mod unify;

pub use cmp::*;
pub use ops::*;

#[doc(inline)]
pub use all::all;
#[doc(inline)]
pub use any::any;
#[doc(inline)]
pub use both::both;
#[doc(inline)]
pub use custom::custom;
#[doc(inline)]
pub use either::either;
#[doc(inline)]
pub use lazy::lazy;
#[doc(inline)]
pub use project::*;
#[doc(inline)]
pub use unify::unify;

#[derive(Clone, Debug)]
pub(crate) enum GoalEnum<'a, D: Domain<'a>> {
    Succeed,
    Fail,
    UnifyIn(D::Value, D::Value),
    Fork(Rc<dyn Fork<'a, D> + 'a>),
    Constraint(Rc<dyn Constraint<'a, D> + 'a>),

    Both(Box<GoalEnum<'a, D>>, Box<GoalEnum<'a, D>>),
    All(Vec<GoalEnum<'a, D>>),
    Lazy(lazy::Lazy<'a, D>),
    Custom(custom::Custom<'a, D>),
}

/// A container of one of many possible types of [goals](crate::goals).
///
/// Values of this type are typically constructed with one of the many
/// [constructor functions](crate::goals#functions) and
/// [macros](crate::goals#macros). These high level methods provide automatic
/// [value](crate::value) wrapping through [`IntoVal`](crate::value::IntoVal)
/// and other niceties.
#[derive(Clone, Debug)]
pub struct Goal<'a, D: Domain<'a>>(GoalEnum<'a, D>);

impl<'a, D: Domain<'a> + 'a> GoalEnum<'a, D> {
    fn apply(self, state: State<'a, D>) -> Option<State<'a, D>> {
        match self {
            GoalEnum::Succeed => Some(state),
            GoalEnum::Fail => None,
            GoalEnum::UnifyIn(a, b) => unify::run(state, a, b),
            GoalEnum::Fork(fork) => state.fork(fork),
            GoalEnum::Constraint(constraint) => state.constrain(constraint),
            GoalEnum::Both(a, b) => both::run(state, *a, *b),
            GoalEnum::All(goals) => all::run(state, goals),
            GoalEnum::Lazy(lazy) => lazy.run(state),
            GoalEnum::Custom(custom) => custom.run(state),
        }
    }
}

impl<'a, D: Domain<'a> + 'a> Goal<'a, D> {
    /// Create a Goal that always succeeds.
    ///
    /// # Example
    /// ```
    /// use canrun::{Goal, all, unify, var};
    /// use canrun::example::I32;
    ///
    /// let x = var();
    /// let goal: Goal<I32> = all![unify(x, 1), Goal::succeed()];
    /// let result: Vec<_> = goal.query(x).collect();
    /// assert_eq!(result, vec![1])
    /// ```
    pub fn succeed() -> Self {
        Goal(GoalEnum::Succeed)
    }

    /// Create a Goal that always fails.
    ///
    /// # Example
    /// ```
    /// use canrun::{Goal, all, unify, var};
    /// use canrun::example::I32;
    ///
    /// let x = var();
    /// let goal: Goal<I32> = all![unify(x, 1), Goal::fail()];
    /// let result: Vec<_> = goal.query(x).collect();
    /// assert_eq!(result, vec![])
    /// ```
    pub fn fail() -> Self {
        Goal(GoalEnum::Fail)
    }

    /// Create a goal containing a [`Fork` object](crate::state::Fork).
    pub fn fork<F: Fork<'a, D> + 'a>(fork: F) -> Self {
        Goal(GoalEnum::Fork(Rc::new(fork)))
    }

    /// Create a goal containing a [`Constraint`
    /// object](crate::state::Constraint).
    pub fn constraint<F: Constraint<'a, D> + 'a>(constraint: F) -> Self {
        Goal(GoalEnum::Constraint(Rc::new(constraint)))
    }

    /// Create a Goal that only succeeds if all sub-goals succeed.
    ///
    /// This constructor takes anything that implements
    /// [`IntoIterator`](std::iter::IntoIterator) for a compatible goal type.
    /// See the [`all!`](./macro.all.html) macro for a slightly higher level
    /// interface.
    ///
    /// # Example
    /// ```
    /// use canrun::{Goal, all, unify, var};
    /// use canrun::example::I32;
    ///
    /// let x = var();
    /// let y = var();
    /// let goal: Goal<I32> = Goal::all(vec![unify(y, x), unify(1, x), unify(y, 1)]);
    /// let result: Vec<_> = goal.query((x, y)).collect();
    /// assert_eq!(result, vec![(1, 1)])
    /// ```
    pub fn all<I: IntoIterator<Item = Goal<'a, D>>>(goals: I) -> Self {
        Goal(GoalEnum::All(goals.into_iter().map(|g| g.0).collect()))
    }

    /// Create a Goal that yields a state for every successful
    /// sub-goal.
    ///
    /// This constructor takes anything that implements
    /// [`IntoIterator`](std::iter::IntoIterator) for a compatible goal type.
    /// See the [`any!`](./macro.any.html) macro for a slightly higher level
    /// interface.
    ///
    /// # Example
    /// ```
    /// use canrun::{Goal, any, unify, var};
    /// use canrun::example::I32;
    ///
    /// let x = var();
    /// let goal: Goal<I32> = Goal::any(vec![unify(x, 1), unify(x, 2), unify(x, 3)]);
    /// let result: Vec<_> = goal.query(x).collect();
    /// assert_eq!(result, vec![1, 2, 3])
    /// ```
    pub fn any<I: IntoIterator<Item = Goal<'a, D>>>(goals: I) -> Self {
        Goal::fork(any::Any {
            goals: goals.into_iter().map(|g| g.0).collect(),
        })
    }

    /// Apply the Goal to an existing state.
    ///
    /// This will update the state, but not iterate through the possible
    /// resolved states. For this you still need to use the
    /// [`.iter_resolved()`](IterResolved::iter_resolved()) interface or
    /// [`.query()`](Goal::query()).
    ///
    /// # Example
    /// ```
    /// use canrun::{Goal, State, unify, var};
    /// use canrun::example::I32;
    ///
    /// let x = var();
    /// let state = State::new();
    /// let goal: Goal<I32> = unify(x, 1);
    /// let state: Option<State<I32>> = goal.apply(state);
    /// ```
    pub fn apply(self, state: State<'a, D>) -> Option<State<'a, D>> {
        self.0.apply(state)
    }

    /// Use the [query](crate::Query) interface to get an iterator of result
    /// values.
    ///
    /// This is a shorthand for creating a new state, applying the goal and
    /// calling [`.query()`](crate::Query) on the resulting state.
    ///
    /// # Example:
    /// ```
    /// use canrun::{Goal, unify, var};
    /// use canrun::example::I32;
    ///
    /// let x = var();
    /// let goal: Goal<I32> = unify(x, 1);
    /// let result: Vec<_> = goal.query(x).collect();
    /// assert_eq!(result, vec![1])
    /// ```
    pub fn query<Q>(self, query: Q) -> Box<dyn Iterator<Item = Q::Reified> + 'a>
    where
        Q: ReifyIn<'a, D> + 'a,
    {
        Query::query(self, query)
    }
}

impl<'a, D: Domain<'a> + 'a> IterResolved<'a, D> for Goal<'a, D> {
    fn iter_resolved(self) -> ResolvedStateIter<'a, D> {
        self.apply(State::new()).iter_resolved()
    }
}