prolog

package module
v0.8.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 1, 2022 License: MIT Imports: 9 Imported by: 33

README

prolog - the only reasonable scripting engine for Go

Go Reference Actions Status Go Report Card codecov Mentioned in Awesome Go

What is this?

ichiban/prolog is an embeddable scripting language for Go. Unlike any other scripting engines, ichiban/prolog implements logic programming language Prolog.

  • Easy to reason about: based on first-order logic
  • Easy to adopt: database/sql-like Go API
  • Intelligent: full-featured Prolog implementation
  • Highly customizable: sandboxing, custom predicates

ichiban/prolog vs otto vs go-lua

prolog otto go-lua
Language ISO Prolog ECMA Script Lua
Paradigm 🎓 Logic Object-oriented Object-oriented
Go API 😻 database/sql-like original original
Declarative
Sandboxing

Getting started

Install latest version
go get -u github.com/ichiban/prolog@latest
Usage
Instantiate an interpreter
p := prolog.New(nil, nil)

Or, if you want to expose standard input/output to your interpreter:

p := prolog.New(os.Stdin, os.Stdout)

Or, if you want a secure interpreter without any builtin predicates:

// See examples/sandboxing/main.go for details.
p := new(prolog.Interpreter)
Load a Prolog program
if err := p.Exec(`

:- [abc].              % Load file 'abc' or 'abc.pl'.

:- ['/path/to/abc'].   % Load file '/path/to/abc' or '/path/to/abc.pl'.
                       % You need to quote to contain / in the path.

:- [library(dcg)].     % Load library 'library(dcg)'.
                       % See examples/dcg/main.go for a complete example.

human(socrates).       % This is a fact.
mortal(X) :- human(X). % This is a rule.

`); err != nil {
	panic(err)
}
Run the Prolog program
// Prolog program invocation takes a form of query.
sols, err := p.Query(`mortal(Who).`)
if err != nil {
	panic(err)
}
defer sols.Close()

// Iterates over solutions.
for sols.Next() {
	// Prepare a struct with fields which name corresponds with a variable in the query.
	var s struct {
		Who string
	}
	if err := sols.Scan(&s); err != nil {
		panic(err)
	}
	fmt.Printf("Who = %s\n", s.Who)
	// ==> Who = socrates
}

Built-in Predicates

Category Indicator ISO? Description Implemented in
Control Constructs true * Always succeeds. Prolog
fail * Always fails. Prolog
false Synonym for fail. Prolog
call(Goal) * Calls Goal. Go
! * Cut. Prolog
P, Q * Conjunction. Prolog
P; Q * Not only disjunction but also If->Then;Else is supported. Prolog
If->Then * If->Then. Prolog
catch(Goal, Catcher, Recover) * Calls Goal. If an exception is raised and unifies with Catcher, calls Recover. Go
throw(Exception) * Raises Exception. Go
\+Goal * Succeeds if Goal fails. Go
once(Goal) * Calls Goal at most once. Prolog
repeat * Repeats until the proceeding code succeeds. Go
halt(Status) * Terminates the host program with exit code Status. Go
halt * Equivalent to halt(0). Prolog
Unification Term1 = Term2 * Unifies Term1 with Term2. Go
unify_with_occurs_check(Term1, Term2) * Unifies Term1 with Term2 if it doesn't create cyclic terms. Go
Term1 \= Term2 * Not unifiable. Prolog
Type Testing var(Term) * Succeeds if Term is a variable. Go
atom(Term) * Succeeds if Term is an atom. Go
integer(Term) * Succeeds if Term is an integer. Go
float(Term) * Succeeds if Term is a float. Go
atomic(Term) * Succeeds if Term is neither a variable nor compound. Prolog
compound(Term) * Succeeds if Term is a compound. Go
nonvar(Term) * Succeeds if Term is not a variable. Prolog
number(Term) * Succeeds if either integer(Term) or float(Term). Prolog
Term Processing functor(Term, Name, Arity) * Succeeds if Term has a name Name and arity Arity. Go
arg(Arg, Term, Value) * Succeeds if the Arg-th argument of Term unifies with Value. Go
Term =.. List * Succeeds if List is a list of the functor and arguments of Term. Go
copy_term(In, Out) * Creates a copy of In and unifies it with Out. Go
compare(Order, Term1, Term2) * Compares Term and Term2 and unifies Order with either <, =, or >. Go
Term1 @=< Term2 * Either Term1 == Term2 or Term1 @< Term2. Prolog
Term1 == Term2 * Equivalent to compare(=, Term1, Term2). Prolog
Term1 \== Term2 * Equivalent to \+compare(=, Term1, Term2). Prolog
Term1 @< Term2 * Equivalent to compare(<, Term1, Term2). Prolog
Term1 @> Term2 * Equivalent to compare(>, Term1, Term2). Prolog
Term1 @>= Term2 * Either Term1 == Term2 or Term1 @> Term2. Prolog
Arithmetic Number is Expression * Evaluates Expression and unifies the result with Number. Go
Exp1 =:= Exp2 * Succeeds if both Exp1 and Exp2 evaluate to the same number. Go
Exp1 =\= Exp2 * Succeeds unless both Exp1 and Exp2 evaluate to the same number. Go
Exp1 < Exp2 * Succeeds if Exp1 evaluates to a number that is less than what Exp2 evaluates to. Go
Exp1 =< Exp2 * Either Exp1 == Exp2 or Exp1 < Exp2. Go
Exp1 > Exp2 * Succeeds if Exp1 evaluates to a number that is greater than what Exp2 evaluates to. Go
Exp1 >= Exp2 * Either Exp1 == Exp2 or Exp1 > Exp2. Go
Clause dynamic(Name/Arity) * Tells the interpreter that the predicate indicated by Name/Arity is dynamic. Go
built_in(Name/Arity) Tells the interpreter that the predicate indicated by Name/Arity is built-in. Go
clause(Head, Body) * Succeeds if Head and Body unify with a clause. Go
current_predicate(Name/Arity) * Succeeds if the predicate indicated by Name/Arity defined. Go
asserta(Term) * Prepends Term to the clauses. Go
assertz(Term) * Appends Term to the clauses. Go
retract(Term) * Remove a clause that unifies with Term. Go
abolish(Name/Arity) * Remove the predicate indicated by Name/Arity. Go
All Solutions findall(Template, Goal, List) * Lists all Template for each solution of Goal and unifies it with List. Go
bagof(Template, Goal, Bag) * Creates a bag (multiset) of Template for each solution of Goal and unifies it with Bag. Go
setof(Template, Goal, Set) * Creates a set of Template for each solution of Goal and unifies it with Set. Go
Stream current_input(Stream) * Unifies Stream with the current input stream. Go
current_output(Stream) * Unifies Stream with the current output stream. Go
set_input(Stream) * Sets the current input stream to Stream. Go
set_output(Stream) * Sets the current output stream to Stream. Go
open(File, Mode, Stream, Options) * Creates a stream of Mode by opening File and unifies it with Stream. Go
open(File, Mode, Stream) * Equivalent to open(File, Mode, Stream, []). Prolog
close(Stream, Options) * Closes Stream. If [force(true)] is provided as Options, ignores errors. Go
close(Stream) * Equivalent to close(Stream, []). Prolog
stream_property(Stream, Property) * Unifies Property with a stream property of Stream. Go
at_end_of_stream(Stream) * Succeeds if Stream is at the end of the stream. Prolog
at_end_of_stream * Equivalent to current_input_stream(S), at_end_of_stream(S) Prolog
set_stream_position(Stream, Position) * Sets the position of Stream to Position. Go
Character I/O get_char(Stream, Char) * Unifies Char with a single-rune atom of the next rune from Stream. Go
get_char(Char) * Equivalent to current_input(S), get_char(S, Char). Prolog
get_code(Stream, Code) * Unifies Code with an integer of the next rune from Stream. Prolog
get_code(Code) * Equivalent to current_input(S), get_code(S, Code). Prolog
peek_char(Stream, Char) * Similar to get_char(Stream, Char) but doesn't consume the next rune. Go
peek_char(Char) * Equivalent to current_input(S), peek_char(S, Char). Prolog
peek_code(Stream, Code) * Similar to get_code(Stream, Code) but doens't consume the next rune. Prolog
peek_code(Code) * Equivalent to current_input(S), peek_code(S, Code). Prolog
put_char(Stream, Char) * Writes a single-rune atom Char to Stream. Prolog
put_char(Char) * Equivalent to current_output(S), put_char(S, Char). Prolog
put_code(Stream, Code) * Writes a rune represented by integer Code to Stream. Go
put_code(Code) * Equivalent to current_output(S), put_code(S, Code). Prolog
nl(Stream) * Writes a newline to Stream. Prolog
nl * Equivalent to current_output(S), nl(S). Prolog
Binary I/O get_byte(Stream, Byte) * Unifies Byte with the next byte from Stream. Go
get_byte(Byte) * Equivalent to current_input(S), get_byte(S, Byte). Prolog
peek_byte(Stream, Byte) * Similar to get_byte(Stream, Byte) but doesn't consume the next byte. Go
peek_byte(Byte) * Equivalent to current_input(S), peek_byte(S, Byte). Prolog
put_byte(Stream, Byte) * Writes a byte represented by an integer Byte to Stream. Go
put_byte(Byte) * Equivalent to current_output(S), put_byte(S, Byte). Prolog
Term I/O read_term(Stream, Term, Options) * Reads a term from Stream and unifies Term with it. Go
read_term(Term, Options) * Equivalent to current_input(S), read_stream(S, Term, Options) Prolog
read(Stream, Term) * Equivalent to read_term(Stream, Term, []). Prolog
read(Term) * Equivalent to current_input(S), read(S, Term). Prolog
write_term(Stream, Term, Options) * Write Term to Stream. Go
write_term(Term, Options) * Equivalent to current_output(S), write_term(S, Term, Options). Prolog
write(Stream, Term) * Equivalent to write_term(Stream, Term, []). Prolog
write(Term) * Equivalent to current_output(S), write(S, Term). Prolog
writeq(Stream, Term) * Equivalent to write_term(Stream, Term, [quoted(true), numbervars(true)]). Prolog
writeq(Term) * Equivalent to current_output(S), writeq(S, Term). Prolog
write_canonical(Stream, Term) * Equivalent to write_term(Stream, Term, [quoted(true), ignore_ops(true)]). Prolog
write_canonical(Term) * Equivalent to current_output(S), write_canonical(S, Term). Prolog
Operator op(Priority, Specifier, Name) * Declares Name is an operator of Priority. Specifier is one of fx, fy, xf, yf, xfx, xfy, or yfx. Go
current_op(Priority, Specifier, Name) * Unifies an operator of Priority, Specifier, and Name. Go
Char Conversion char_conversion(In, Out) * Declares a char conversion from In to Out. Go
current_char_conversion(In, Out) * Unifies a char conversion from In to Out. Go
Atom Processing atom_length(Atom, Length) * Succeeds if the length of Atom unifies with Length. Go
atom_concat(Atom1, Atom2, Atom3) * Succeeds if Atom3 is a concatination of Atom1 and Atom2. Go
sub_atom(Atom, Before, Length, After, SubAtom) * Succeeds if SubAtom can be unified with a sub atom of Atom where Before is the number of runes before SubAtom, Length is the length of SubAtom, and After is the number of runes after SubAtom. Go
atom_chars(Atom, Chars) * Succeeds if Atom consists of single-rune atoms in the list Chars. Go
atom_codes(Atom, Codes) * Similar to atom_chars(Atom, Chars) but integers represents runes of the atom. Go
char_code(Char, Code) * Succeeds if a single-rune atom Atom and an integer Code represents the same rune. Go
number_chars(Number, Chars) * Succeeds if Number is a number which string representation consists of single-rune atoms in a list Chars. Go
number_codes(Number, Codes) * Similar to number_chars(Number, Chars) but a list of integers. Go
Flag set_prolog_flag(Flag, Value) * Sets a Prolog flag Flag to Value. Go
current_prolog_flag(Flag, Value) * Succeeds if a Prolog flag Flag is set to Value. Go
Program consult(File) Loads files or libraries. File can be an atom describing a file path, library(Name) describing a library, or a list of them. Go
.(File, Files) Equivalent to consult(.(File, Files)). Prolog
List Processing append(List1, List2, List3) Succeeds if List3 is the concatination of List1 and List2. Prolog
member(Elem, List) Succeeds if Elem is a member of List. Prolog
length(List, Length) Succeeds if Length is the length of List. Prolog
Term Expansion expand_term(In, Out) Unifies Out with an expanded term for In. Go
Environment Variable environ(Key, Value) Succeeds if an environment varialble Key has a value Value. Go

License

Distributed under the MIT license. See LICENSE for more information.

Contributing

See ARCHITECTURE.md for architecture details.

  1. Fork it (https://github.com/ichiban/prolog/fork)
  2. Create your feature branch (git checkout -b feature/fooBar)
  3. Commit your changes (git commit -am 'Add some fooBar')
  4. Push to the branch (git push origin feature/fooBar)
  5. Create a new Pull Request

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrClosed = errors.New("closed")

ErrClosed indicates the Solutions are already closed and unable to perform the operation.

View Source
var ErrNoSolutions = errors.New("no solutions")

ErrNoSolutions indicates there's no solutions for the query.

Functions

func Register added in v0.5.0

func Register(name string, library func(*Interpreter) error)

Register registers a library. if there's a library with the same name registered, it panics.

Types

type Interpreter added in v0.2.0

type Interpreter struct {
	engine.State
}

Interpreter is a Prolog interpreter. The zero value is a valid interpreter without any predicates/operators defined.

func New added in v0.2.0

func New(in io.Reader, out io.Writer) *Interpreter

New creates a new Prolog interpreter with predefined predicates/operators.

func (*Interpreter) Exec added in v0.2.0

func (i *Interpreter) Exec(query string, args ...interface{}) error

Exec executes a prolog program.

func (*Interpreter) ExecContext added in v0.3.0

func (i *Interpreter) ExecContext(ctx context.Context, query string, args ...interface{}) error

ExecContext executes a prolog program with context.

func (*Interpreter) Query added in v0.2.0

func (i *Interpreter) Query(query string, args ...interface{}) (*Solutions, error)

Query executes a prolog query and returns *Solutions.

func (*Interpreter) QueryContext added in v0.3.0

func (i *Interpreter) QueryContext(ctx context.Context, query string, args ...interface{}) (*Solutions, error)

QueryContext executes a prolog query and returns *Solutions with context.

func (*Interpreter) QuerySolution added in v0.6.0

func (i *Interpreter) QuerySolution(query string, args ...interface{}) *Solution

QuerySolution executes a Prolog query for the first solution.

func (*Interpreter) QuerySolutionContext added in v0.6.0

func (i *Interpreter) QuerySolutionContext(ctx context.Context, query string, args ...interface{}) *Solution

QuerySolutionContext executes a Prolog query with context.

type Solution added in v0.6.0

type Solution struct {
	// contains filtered or unexported fields
}

Solution is the single result of a query.

func (*Solution) Err added in v0.6.0

func (s *Solution) Err() error

Err returns an error that occurred while querying for the Solution, if any.

func (*Solution) Scan added in v0.6.0

func (s *Solution) Scan(dest interface{}) error

Scan copies the variable values of the solution into the specified struct/map.

func (*Solution) Vars added in v0.6.0

func (s *Solution) Vars() []string

Vars returns variable names.

type Solutions added in v0.2.0

type Solutions struct {
	// contains filtered or unexported fields
}

Solutions is the result of a query. Everytime the Next method is called, it searches for the next solution. By calling the Scan method, you can retrieve the content of the solution.

func (*Solutions) Close added in v0.2.0

func (s *Solutions) Close() error

Close closes the Solutions and terminates the search for other solutions.

func (*Solutions) Err added in v0.2.0

func (s *Solutions) Err() error

Err returns the error if exists.

func (*Solutions) Next added in v0.2.0

func (s *Solutions) Next() bool

Next prepares the next solution for reading with the Scan method. It returns true if it finds another solution, or false if there's no further solutions or if there's an error.

func (*Solutions) Scan added in v0.2.0

func (s *Solutions) Scan(dest interface{}) error

Scan copies the variable values of the current solution into the specified struct/map.

func (*Solutions) Vars added in v0.2.0

func (s *Solutions) Vars() []string

Vars returns variable names.

Directories

Path Synopsis
cmd
1pl command
examples
dcg command
hanoi command
sandboxing command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL