AI-Prolog

 view release on metacpan or  search on metacpan

lib/AI/Prolog/Term.pm  view on Meta::CPAN


use constant NULL => 'null';

# Var is a type of term
# A term is a basic data structure in Prolog
# There are three types of terms:
#   1. Values     (i.e., have a functor and arguments)
#   2. Variables  (i.e., unbound)
#   3. References (bound to another variable)

my $VARNUM = 1;

# controls where occurcheck is used in unification.
# In early Java versions, the occurcheck was always performed
# which resulted in lower performance.

my $OCCURCHECK = 0;

sub occurcheck {
    my ( $class, $value ) = @_;
    $OCCURCHECK = $value if defined $value;
    return $OCCURCHECK;
}

# controls printing of lists as [a,b]
# instead of cons(a, cons(b, null))

sub prettyprint {1}

my $CUT = Cut->new(0);
sub CUT {$CUT}

sub new {
    my $proto = shift;
    my $class = CORE::ref $proto || $proto;    # yes, I know what I'm doing
    return $class->_new_var unless @_;
    if ( 2 == @_ ) {    # more common (performance)
        return _new_from_functor_and_arity( $class, @_ )
            unless 'ARRAY' eq CORE::ref $_[1];
    }
    elsif ( 1 == @_ ) {
        my $arg = shift;
        return _new_with_id( $class, $arg )
            if !CORE::ref $arg && $arg =~ /^[[:digit:]]+$/;
        return _new_from_string( $class, $arg ) if !CORE::ref $arg;

#return $arg->_term($class)            if   CORE::ref $arg && $arg->isa(Parser);
    }
    croak("Unknown arguments to Term->new");
}

sub _new_from_string {
    my ( $class, $string ) = @_;
    my $parsed = Parser->new($string)->_term($class);
}

sub _new_var {
    my $class = shift;

    #print "*** _new_var @{[$VARNUM+1]}";
    my $self = bless {
        functor => undef,
        arity   => 0,
        args    => [],

        # if bound is false, $self is a reference to a free variable
        bound => 0,
        varid => $VARNUM++,

        # if bound and deref are both true, $self is a reference to a ref
        deref => 0,
        ref   => undef,

        ID       => undef,
        varname  => undef,
        _results => undef,

        #source  => "_new_var",
    } => $class;
    lock_keys %$self;
    return $self;
}

sub _new_with_id {
    my ( $class, $id ) = @_;

    #print "*** _new_with_id: $id";
    my $self = bless {
        functor => undef,
        arity   => 0,
        args    => [],

        # if bound is false, $self is a reference to a free variable
        bound => 0,
        varid => $id,

        # if bound and deref are both true, $self is a reference to a ref
        deref => 0,
        ref   => undef,

        varname  => undef,
        ID       => undef,
        _results => undef,

        #source  => "_new_with_id: $id",
    } => $class;
    lock_keys %$self;
    return $self;
}

sub _new_from_functor_and_arity {
    my ( $class, $functor, $arity ) = @_;
    my $print_functor = defined $functor ? $functor : 'null';
    confess "undefined arity" unless defined $arity;

    #print "*** _new_from_functor_and_arity: ($print_functor) ($arity)";
    my $self = bless {
        functor => $functor,
        arity   => $arity,
        args    => [],

        # if bound is false, $self is a reference to a free variable
        bound => 1,
        varid => 0,    # XXX ??
             # if bound and deref are both true, $self is a reference to a ref
        deref => 0,
        ref   => undef,

        varname  => undef,
        ID       => undef,
        _results => undef,

        #source  => "_new_from_functor_and_arity: ($print_functor) ($arity)",
    } => $class;
    lock_keys %$self;
    return $self;
}

sub varnum  {$VARNUM}              # class method
sub functor { shift->{functor} }
sub arity   { shift->{arity} }
sub args    { shift->{args} }
sub varid   { shift->{varid} }
sub ref     { shift->{ref} }
sub predicate { sprintf "%s/%d" => $_[0]->getfunctor, $_[0]->getarity }

sub deref {
    my $self = shift;
    while ( $self->{bound} && $self->{deref} ) {
        $self = $self->{ref};
    }
    return $self;
}

sub bound {
    my $self = shift;
    while ( $self->{bound} && $self->{deref} ) {
        $self = $self->{ref};
    }
    return $self->{bound};
}

sub is_bound { shift->bound }

sub traceln {
    my ( $self, $msg ) = @_;
    if ( $self->{trace} ) {
        print "$msg\n";
    }
}

sub dup {
    my $self = shift;
    $self->new( $self->{functor}, $self->{arity} );
}

# bind a variable to a term



( run in 1.064 second using v1.01-cache-2.11-cpan-39bf76dae61 )