///|
/// A Prolog term.
pub enum Term {
/// Named variable.
Var(String)
/// Atom.
Atom(String)
/// Integer number.
Int(Int)
/// Floating-point number.
Float(Double)
/// String.
Str(String)
/// Compound term `functor(arg1, arg2, ...)`.
Compound(String, Array[Term])
} derive(Eq, Debug)
///|
pub extend Term with Eq::{not_equal, equal}
///|
pub extend Term with Debug::{to_repr}
///|
/// The empty list `[]`.
pub fn empty_list() -> Term {
Atom("[]")
}
///|
/// Build a proper list `[a, b, c]` from elements.
pub fn list(elems : ArrayView[Term]) -> Term {
fn go(i : Int) -> Term {
if i >= elems.length() {
Atom("[]")
} else {
Compound(".", [elems[i], go(i + 1)])
}
}
go(0)
}
///|
/// Build a cons cell `[Head | Tail]`.
pub fn cons(head : Term, tail : Term) -> Term {
Compound(".", [head, tail])
}
///|
/// Is this term a proper list?
pub fn Term::is_list(self : Term) -> Bool {
fn go(t : Term) -> Bool {
match t {
Atom("[]") => true
Compound(".", [_, tl]) => go(tl)
_ => false
}
}
go(self)
}
///|
/// Variables occurring in the term, in order of first occurrence.
pub fn Term::free_vars(self : Term) -> Array[String] {
fn go(t : Term, acc : Array[String]) -> Array[String] {
match t {
Var(n) => {
if !acc.iter().any(x => x == n) {
acc.push(n)
}
acc
}
Compound(_, args) => {
let mut a = acc
for x in args {
a = go(x, a)
}
a
}
_ => acc
}
}
go(self, [])
}
///|
/// Construct a variable term.
pub fn variable(name : String) -> Term {
Var(name)
}
///|
/// Construct an atom term.
pub fn atom(name : String) -> Term {
Atom(name)
}
///|
/// Construct an integer term.
pub fn int(value : Int) -> Term {
Int(value)
}
///|
/// Construct a float term.
pub fn float(value : Double) -> Term {
Float(value)
}
///|
/// Construct a string term.
pub fn str(value : String) -> Term {
Str(value)
}
///|
/// Construct a compound term.
pub fn compound(functor : String, args : Array[Term]) -> Term {
Compound(functor, args)
}